Merge "Camera: Propogate onCameraOpened flag at listener registration"
diff --git a/Android.bp b/Android.bp
index 62dce7f..9127966f 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",
@@ -123,7 +124,6 @@
         ":libbluetooth-binder-aidl",
         ":libcamera_client_aidl",
         ":libcamera_client_framework_aidl",
-        ":packagemanager_aidl",
         ":libupdate_engine_aidl",
         ":resourcemanager_aidl",
         ":storaged_aidl",
@@ -155,6 +155,7 @@
         "framework-sdkextensions.stubs.module_lib",
         "framework-statsd.stubs.module_lib",
         "framework-tethering.stubs.module_lib",
+        "framework-uwb.stubs.module_lib",
         "framework-wifi.stubs.module_lib",
     ],
     sdk_version: "module_current",
@@ -177,6 +178,7 @@
         "framework-sdkextensions.impl",
         "framework-statsd.impl",
         "framework-tethering.impl",
+        "framework-uwb.impl",
         "framework-wifi.impl",
         "updatable-media",
     ],
@@ -225,6 +227,7 @@
     name: "framework-internal-utils",
     static_libs: [
         "apex_aidl_interface-java",
+        "packagemanager_aidl-java",
         "framework-protos",
         "updatable-driver-protos",
         "ota_metadata_proto_java",
@@ -250,8 +253,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",
@@ -331,6 +332,7 @@
     ],
     sdk_version: "core_platform",
     static_libs: [
+        "android.hardware.common.fmq-V1-java",
         // TODO(b/184162091)
         "android.hardware.soundtrigger3-V1-java",
         "bouncycastle-repackaged-unbundled",
@@ -344,6 +346,8 @@
         "modules-utils-preconditions",
         "modules-utils-os",
         "framework-permission-aidl-java",
+        "spatializer-aidl-java",
+        "audiopolicy-types-aidl-java",
     ],
 }
 
@@ -559,8 +563,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/OWNERS b/OWNERS
index 03cfac9..ab5bd18 100644
--- a/OWNERS
+++ b/OWNERS
@@ -23,6 +23,9 @@
 # via https://android.git.corp.google.com/All-Projects/+/refs/meta/config/rules.pl.
 per-file */api/*current.txt = *
 
+# Test mapping changes can be made by anyone
+per-file */TEST_MAPPING = *
+
 # Support bulk translation updates
 per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
 
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 44c55c2..1904c1f 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -250,6 +250,7 @@
     "framework-sdkextensions.stubs",
     "framework-statsd.stubs",
     "framework-tethering.stubs",
+    "framework-uwb.stubs",
     "framework-wifi.stubs",
     "i18n.module.public.api.stubs",
 ]
@@ -269,6 +270,7 @@
     "framework-sdkextensions.stubs.system",
     "framework-statsd.stubs.system",
     "framework-tethering.stubs.system",
+    "framework-uwb.stubs.system",
     "framework-wifi.stubs.system",
     "i18n.module.public.api.stubs", // Only has public stubs
 ]
diff --git a/TestProtoLibraries.bp b/TestProtoLibraries.bp
index 8e269d0..9e2a64c 100644
--- a/TestProtoLibraries.bp
+++ b/TestProtoLibraries.bp
@@ -31,6 +31,6 @@
         type: "full",
     },
     errorprone: {
-        javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
+        enabled: false,
     },
 }
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/core/src/android/os/LongArrayMultiStateCounterPerfTest.java b/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java
new file mode 100644
index 0000000..f3d7390
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.os;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.LongArrayMultiStateCounter;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class LongArrayMultiStateCounterPerfTest {
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    /**
+     * A complete line-for-line reimplementation of
+     * {@link }com.android.internal.os.CpuTimeInFreqMultiStateCounter}, only in Java instead of
+     * native.
+     */
+    private static class TestLongArrayMultiStateCounter {
+        private final int mStateCount;
+        private final int mArrayLength;
+        private int mCurrentState;
+        private long mLastStateChangeTimestampMs;
+        private long mLastUpdateTimestampMs;
+
+        private static class State {
+            private long mTimeInStateSinceUpdate;
+            private long[] mCounter;
+        }
+
+        private final State[] mStates;
+        private final long[] mLastTimeInFreq;
+        private final long[] mDelta;
+
+        TestLongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
+                long timestampMs) {
+            mStateCount = stateCount;
+            mArrayLength = arrayLength;
+            mCurrentState = initialState;
+            mLastStateChangeTimestampMs = timestampMs;
+            mLastUpdateTimestampMs = timestampMs;
+            mStates = new State[stateCount];
+            for (int i = 0; i < mStateCount; i++) {
+                mStates[i] = new State();
+                mStates[i].mCounter = new long[mArrayLength];
+            }
+            mLastTimeInFreq = new long[mArrayLength];
+            mDelta = new long[mArrayLength];
+        }
+
+        public void setState(int state, long timestampMs) {
+            if (timestampMs >= mLastStateChangeTimestampMs) {
+                mStates[mCurrentState].mTimeInStateSinceUpdate +=
+                        timestampMs - mLastStateChangeTimestampMs;
+            } else {
+                for (int i = 0; i < mStateCount; i++) {
+                    mStates[i].mTimeInStateSinceUpdate = 0;
+                }
+            }
+            mCurrentState = state;
+            mLastStateChangeTimestampMs = timestampMs;
+        }
+
+        public void updateValue(long[] timeInFreq, long timestampMs) {
+            setState(mCurrentState, timestampMs);
+
+            if (timestampMs > mLastUpdateTimestampMs) {
+                if (delta(mLastTimeInFreq, timeInFreq, mDelta)) {
+                    long timeSinceUpdate = timestampMs - mLastUpdateTimestampMs;
+                    for (int i = 0; i < mStateCount; i++) {
+                        long timeInState = mStates[i].mTimeInStateSinceUpdate;
+                        if (timeInState > 0) {
+                            add(mStates[i].mCounter, mDelta, timeInState, timeSinceUpdate);
+                            mStates[i].mTimeInStateSinceUpdate = 0;
+                        }
+                    }
+                } else {
+                    throw new RuntimeException();
+                }
+            } else if (timestampMs < mLastUpdateTimestampMs) {
+                throw new RuntimeException();
+            }
+            System.arraycopy(timeInFreq, 0, mLastTimeInFreq, 0, mArrayLength);
+            mLastUpdateTimestampMs = timestampMs;
+        }
+
+        private boolean delta(long[] timeInFreq1, long[] timeInFreq2, long[] delta) {
+            if (delta.length != mArrayLength) {
+                throw new RuntimeException();
+            }
+
+            boolean is_delta_valid = true;
+            for (int i = 0; i < mStateCount; i++) {
+                if (timeInFreq2[i] >= timeInFreq1[i]) {
+                    delta[i] = timeInFreq2[i] - timeInFreq1[i];
+                } else {
+                    delta[i] = 0;
+                    is_delta_valid = false;
+                }
+            }
+
+            return is_delta_valid;
+        }
+
+        private void add(long[] counter, long[] delta, long numerator, long denominator) {
+            if (numerator != denominator) {
+                for (int i = 0; i < mArrayLength; i++) {
+                    counter[i] += delta[i] * numerator / denominator;
+                }
+            } else {
+                for (int i = 0; i < mArrayLength; i++) {
+                    counter[i] += delta[i];
+                }
+            }
+        }
+    }
+
+    @Test
+    public void javaImplementation() {
+        TestLongArrayMultiStateCounter counter =
+                new TestLongArrayMultiStateCounter(2, 4, 0, 1000);
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        long time = 1000;
+        long[] timeInFreq = {100, 200, 300, 400};
+        while (state.keepRunning()) {
+            counter.setState(1, time);
+            counter.setState(0, time + 1000);
+            counter.updateValue(timeInFreq, time + 2000);
+            time += 10000;
+        }
+    }
+
+    @Test
+    public void nativeImplementation() {
+        LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        long time = 1000;
+        LongArrayMultiStateCounter.LongArrayContainer timeInFreq =
+                new LongArrayMultiStateCounter.LongArrayContainer(4);
+        timeInFreq.setValues(new long[]{100, 200, 300, 400});
+        while (state.keepRunning()) {
+            counter.setState(1, time);
+            counter.setState(0, time + 1000);
+            counter.updateValues(timeInFreq, time + 2000);
+            time += 10000;
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index 90dca25..f9ddf9a 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -191,7 +191,7 @@
     }
 
     class ParallelParser2(cacher: PackageCacher2? = null)
-        : ParallelParser<ParsingPackageRead>(cacher) {
+        : ParallelParser<ParsingPackageImpl>(cacher) {
         val input = ThreadLocal.withInitial {
             // For testing, just disable enforcement to avoid hooking up to compat framework
             ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
@@ -211,6 +211,7 @@
 
         override fun parseImpl(file: File) =
                 parser.parsePackage(input.get()!!.reset(), file, 0).result
+                        as ParsingPackageImpl
     }
 
     abstract class PackageCacher<PackageType : Parcelable>(private val cacheDir: File) {
@@ -266,7 +267,7 @@
     /**
      * Re-implementation of the server side PackageCacher, as it's inaccessible here.
      */
-    class PackageCacher2(cacheDir: File) : PackageCacher<ParsingPackageRead>(cacheDir) {
+    class PackageCacher2(cacheDir: File) : PackageCacher<ParsingPackageImpl>(cacheDir) {
         override fun fromParcel(parcel: Parcel) = ParsingPackageImpl(parcel)
     }
 }
diff --git a/apct-tests/perftests/core/src/android/util/ArrayMapPerfTest.java b/apct-tests/perftests/core/src/android/util/ArrayMapPerfTest.java
new file mode 100644
index 0000000..b93a6ea
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/ArrayMapPerfTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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 android.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.BiConsumer;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ArrayMapPerfTest {
+    private static final int NUM_ITERATIONS = 100;
+    private static final int SET_SIZE_SMALL = 10;
+    private static final int SET_SIZE_LARGE = 50;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testForEach_Small() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        BiConsumer<String, Integer> consumer = (s, i) -> {
+        };
+        while (state.keepRunning()) {
+            for (int i = 0; i < NUM_ITERATIONS; ++i) {
+                ArrayMap<String, Integer> map = new ArrayMap<>();
+                for (int j = 0; j < SET_SIZE_SMALL; j++) {
+                    map.put(Integer.toString(j), j);
+                }
+                map.forEach(consumer);
+            }
+        }
+    }
+
+    @Test
+    public void testForEach_Large() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        BiConsumer<String, Integer> consumer = (s, i) -> {
+        };
+        while (state.keepRunning()) {
+            for (int i = 0; i < NUM_ITERATIONS; ++i) {
+                ArrayMap<String, Integer> map = new ArrayMap<>();
+                for (int j = 0; j < SET_SIZE_LARGE; j++) {
+                    map.put(Integer.toString(j), j);
+                }
+                map.forEach(consumer);
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index 8e342f3..bec3cc9 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -29,7 +29,7 @@
         <option name="push-file" key="trace_config_multi_user.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
         <!--Install the content provider automatically when we push some file in sdcard folder.-->
         <!--Needed to avoid the installation during the test suite.-->
-        <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
+        <option name="push-file" key="trace_config_multi_user.textproto" value="/sdcard/sample.textproto" />
     </target_preparer>
 
     <!-- Needed for pulling the collected trace config on to the host -->
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
index 8305d3f..a9f720a 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
@@ -44,6 +44,11 @@
 
     private Throwable mFirstFailure = null;
 
+    /**
+     * Starts a new run. Also responsible for finalising the calculations from the previous run,
+     * if there was one; therefore, any previous run must not be {@link #pauseTiming() paused} when
+     * this is called.
+     */
     public boolean keepRunning() {
         switch (mState) {
             case NOT_STARTED:
@@ -88,7 +93,31 @@
         mState = PAUSED;
     }
 
+    /**
+     * Resumes the timing after a previous {@link #pauseTiming()}.
+     * First waits for the system to be idle prior to resuming.
+     *
+     * If this is called at the end of the run (so that no further timing is actually desired before
+     * {@link #keepRunning()} is called anyway), use {@link #resumeTimingForNextIteration()} instead
+     * to avoid unnecessary waiting.
+     */
     public void resumeTiming() {
+        ShellHelper.runShellCommand("am wait-for-broadcast-idle");
+        resumeTimer();
+    }
+
+    /**
+     * Resume timing in preparation for a possible next run (rather than to continue timing the
+     * current run).
+     *
+     * It is equivalent to {@link #resumeTiming()} except that it skips steps that
+     * are unnecessary at the end of a trial (namely, waiting for the system to idle).
+     */
+    public void resumeTimingForNextIteration() {
+        resumeTimer();
+    }
+
+    private void resumeTimer() {
         if (mState != PAUSED) {
             throw new IllegalStateException("Unable to resume the runner: already running");
         }
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 42ef80c..6e2742c 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -26,6 +26,7 @@
 import android.app.UserSwitchObserver;
 import android.app.WaitResult;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -87,6 +88,10 @@
 public class UserLifecycleTests {
     private static final String TAG = UserLifecycleTests.class.getSimpleName();
 
+    /** Max runtime for each test (including all runs within that test). */
+    // No point exceeding 10 minutes, since device would likely be considered non-responsive anyway.
+    private static final long TIMEOUT_MAX_TEST_TIME_MS = 9 * 60_000;
+
     private static final int TIMEOUT_IN_SECOND = 30;
     private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
 
@@ -142,7 +147,8 @@
         }
     }
 
-    @Test
+    /** Tests creating a new user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void createUser() {
         while (mRunner.keepRunning()) {
             Log.i(TAG, "Starting timer");
@@ -151,11 +157,12 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    @Test
+    /** Tests creating and starting a new user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void createAndStartUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             Log.i(TAG, "Starting timer");
@@ -171,22 +178,23 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     /**
+     * Tests starting an uninitialized user.
      * Measures the time until ACTION_USER_STARTED is received.
      */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void startUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
             final CountDownLatch latch = new CountDownLatch(1);
             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             mIam.startUserInBackground(userId);
             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
@@ -194,20 +202,21 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     /**
+     * Tests starting & unlocking an uninitialized user.
      * Measures the time until unlock listener is triggered and user is unlocked.
      */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void startAndUnlockUser() {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             // Waits for UserState.mUnlockProgress.finish().
             startUserInBackgroundAndWaitForUnlock(userId);
@@ -215,18 +224,19 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    @Test
+    /** Tests switching to an uninitialized user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void switchUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
             final int userId = createUserNoFlags();
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             switchUser(userId);
 
@@ -234,12 +244,12 @@
             Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    /** Tests switching to an already-created, but no-longer-running, user. */
-    @Test
+    /** Tests switching to a previously-started, but no-longer-running, user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void switchUser_stopped() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
@@ -247,8 +257,8 @@
             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
             final CountDownLatch latch = new CountDownLatch(1);
             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             mAm.switchUser(testUser);
             waitForLatch("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, latch);
@@ -258,19 +268,19 @@
             Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(testUser);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    /** Tests switching to an already-created already-running non-owner user. */
-    @Test
+    /** Tests switching to an already-created already-running non-owner background user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void switchUser_running() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             switchUser(testUser);
 
@@ -278,32 +288,37 @@
             Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(testUser);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    @Test
+    /** Tests stopping a background user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void stopUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
-            final CountDownLatch latch = new CountDownLatch(1);
-            registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
+            final CountDownLatch latch1 = new CountDownLatch(1);
+            final CountDownLatch latch2 = new CountDownLatch(1);
+            registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch1, userId);
+            registerMediaBroadcastReceiver(latch2, userId);
             mIam.startUserInBackground(userId);
-            waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
-            Log.i(TAG, "Starting timer");
+            waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch1);
+            waitForLatch("Failed to achieve ACTION_MEDIA_MOUNTED for user " + userId, latch2);
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             stopUser(userId, false);
 
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    @Test
+    /** Tests reaching LOOKED_BOOT_COMPLETE when switching to uninitialized user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void lockedBootCompleted() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
@@ -311,8 +326,8 @@
             final int userId = createUserNoFlags();
             final CountDownLatch latch = new CountDownLatch(1);
             registerUserSwitchObserver(null, latch, userId);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             mAm.switchUser(userId);
             waitForLatch("Failed to achieve onLockedBootComplete for user " + userId, latch);
@@ -321,17 +336,21 @@
             Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    @Test
+    /** Tests stopping an ephemeral foreground user. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void ephemeralUserStopped() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
             final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
+            final CountDownLatch prelatch = new CountDownLatch(1);
+            registerMediaBroadcastReceiver(prelatch, userId);
             switchUser(userId);
+            waitForLatch("Failed to achieve ACTION_MEDIA_MOUNTED for user " + userId, prelatch);
             final CountDownLatch latch = new CountDownLatch(1);
             InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
                 @Override
@@ -344,8 +363,8 @@
             }, new IntentFilter(Intent.ACTION_USER_STOPPED));
             final CountDownLatch switchLatch = new CountDownLatch(1);
             registerUserSwitchObserver(switchLatch, null, startUser);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             mAm.switchUser(startUser);
             waitForLatch("Failed to achieve ACTION_USER_STOPPED for user " + userId, latch);
@@ -358,12 +377,12 @@
                 Log.e(TAG, "Thread interrupted unexpectedly while waiting for switch.", e);
             }
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     /** Tests creating a new profile. */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileCreate() {
         assumeTrue(mHasManagedUserFeature);
 
@@ -375,32 +394,32 @@
             Log.i(TAG, "Stopping timer");
             attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    /** Tests starting (unlocking) a newly-created profile. */
-    @Test
+    /** Tests starting (unlocking) an uninitialized profile. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileUnlock() {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
-    @Test
+    /** Tests starting (unlocking) a previously-started, but no-longer-running, profile. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileUnlock_stopped() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
@@ -410,22 +429,22 @@
             // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
             startUserInBackgroundAndWaitForUnlock(userId);
             stopUser(userId, true);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     /**
-     * Tests starting (unlocking) and launching an already-installed app in a newly-created profile.
+     * Tests starting (unlocking) & launching an already-installed app in an uninitialized profile.
      */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileUnlockAndLaunchApp() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
@@ -434,8 +453,8 @@
             final int userId = createManagedProfile();
             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
@@ -443,17 +462,17 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     /**
      * Tests starting (unlocking) and launching a previously-launched app
-     * in an already-created, but no-longer-running, profile.
+     * in a previously-started, but no-longer-running, profile.
      * A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
      * {@link #managedProfileUnlock_stopped}}.
      */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileUnlockAndLaunchApp_stopped() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
@@ -466,8 +485,8 @@
             startApp(userId, DUMMY_PACKAGE_NAME);
             stopUser(userId, true);
             SystemClock.sleep(1_000); // 1 second cool-down before re-starting profile.
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
@@ -475,27 +494,27 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
-    /** Tests installing a pre-existing app in a newly-created profile. */
-    @Test
+    /** Tests installing a pre-existing app in an uninitialized profile. */
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileInstall() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
@@ -503,15 +522,15 @@
      * Tests creating a new profile, starting (unlocking) it, installing an app,
      * and launching that app in it.
      */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileCreateUnlockInstallAndLaunchApp() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
-            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             final int userId = createManagedProfile();
             startUserInBackgroundAndWaitForUnlock(userId);
@@ -521,34 +540,37 @@
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     /** Tests stopping a profile. */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileStopped() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
+            final CountDownLatch prelatch = new CountDownLatch(1);
+            registerMediaBroadcastReceiver(prelatch, userId);
             startUserInBackgroundAndWaitForUnlock(userId);
-            Log.i(TAG, "Starting timer");
+            waitForLatch("Failed to achieve ACTION_MEDIA_MOUNTED for user " + userId, prelatch);
             mRunner.resumeTiming();
+            Log.i(TAG, "Starting timer");
 
             stopUser(userId, true);
 
             mRunner.pauseTiming();
             Log.i(TAG, "Stopping timer");
             removeUser(userId);
-            mRunner.resumeTiming();
+            mRunner.resumeTimingForNextIteration();
         }
     }
 
     // TODO: This is just a POC. Do this properly and add more.
     /** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileUnlock_usingWhitelist() {
         assumeTrue(mHasManagedUserFeature);
         final int origMode = getUserTypePackageWhitelistMode();
@@ -559,22 +581,22 @@
             while (mRunner.keepRunning()) {
                 mRunner.pauseTiming();
                 final int userId = createManagedProfile();
-                Log.i(TAG, "Starting timer");
                 mRunner.resumeTiming();
+                Log.i(TAG, "Starting timer");
 
                 startUserInBackgroundAndWaitForUnlock(userId);
 
                 mRunner.pauseTiming();
                 Log.i(TAG, "Stopping timer");
                 removeUser(userId);
-                mRunner.resumeTiming();
+                mRunner.resumeTimingForNextIteration();
             }
         } finally {
             setUserTypePackageWhitelistMode(origMode);
         }
     }
     /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */
-    @Test
+    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
     public void managedProfileUnlock_notUsingWhitelist() {
         assumeTrue(mHasManagedUserFeature);
         final int origMode = getUserTypePackageWhitelistMode();
@@ -584,15 +606,15 @@
             while (mRunner.keepRunning()) {
                 mRunner.pauseTiming();
                 final int userId = createManagedProfile();
-                Log.i(TAG, "Starting timer");
                 mRunner.resumeTiming();
+                Log.i(TAG, "Starting timer");
 
                 startUserInBackgroundAndWaitForUnlock(userId);
 
                 mRunner.pauseTiming();
                 Log.i(TAG, "Stopping timer");
                 removeUser(userId);
-                mRunner.resumeTiming();
+                mRunner.resumeTimingForNextIteration();
             }
         } finally {
             setUserTypePackageWhitelistMode(origMode);
@@ -689,9 +711,12 @@
         // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
         final int testUser = createUserNoFlags();
         final CountDownLatch latch1 = new CountDownLatch(1);
+        final CountDownLatch latch2 = new CountDownLatch(1);
         registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
+        registerMediaBroadcastReceiver(latch2, testUser);
         mAm.switchUser(testUser);
         waitForLatch("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser, latch1);
+        waitForLatch("Failed to achieve initial ACTION_MEDIA_MOUNTED for user " + testUser, latch2);
 
         // Second, switch back to origUser, waiting merely for switchUser() to finish
         switchUser(origUser);
@@ -774,6 +799,37 @@
         }, UserHandle.of(userId), new IntentFilter(action), null, null);
     }
 
+    /**
+     * Register for a broadcast to indicate that Storage has processed the given user.
+     * Without this as part of setup, for tests dealing with already-switched users, Storage may not
+     * have finished, making the resulting processing inconsistent.
+     *
+     * Strictly speaking, the receiver should always be unregistered afterwards, but we don't
+     * necessarily bother since receivers from failed tests will be removed on test uninstallation.
+     */
+    private void registerMediaBroadcastReceiver(final CountDownLatch latch, final int userId) {
+        final String action = Intent.ACTION_MEDIA_MOUNTED;
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(action);
+        filter.addDataScheme(ContentResolver.SCHEME_FILE);
+
+        final Context context = InstrumentationRegistry.getContext();
+        context.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String data = intent.getDataString();
+                if (action.equals(intent.getAction())) {
+                    Log.d(TAG, "Received ACTION_MEDIA_MOUNTED with " + data);
+                    if (data != null && data.contains("/" + userId)) {
+                        latch.countDown();
+                        context.unregisterReceiver(this);
+                    }
+                }
+            }
+        }, UserHandle.of(userId), filter, null, null);
+    }
+
     private class ProgressWaiter extends IProgressListener.Stub {
         private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
 
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/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
index d493a1c..272e12d 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
@@ -96,6 +96,17 @@
         return Collections.unmodifiableMap(mAll);
     }
 
+    /**
+     * Asserts that this {@link AppSearchBatchResult} has no failures.
+     *
+     * @hide
+     */
+    public void checkSuccess() {
+        if (!isSuccess()) {
+            throw new IllegalStateException("AppSearchBatchResult has failures: " + this);
+        }
+    }
+
     @Override
     @NonNull
     public String toString() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
index 10e014b..d6d5315 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
@@ -71,7 +71,7 @@
 
     /**
      * Checks the setSchema() call won't delete any types or has incompatible types after all {@link
-     * Migrator} has been triggered..
+     * Migrator} has been triggered.
      */
     public static void checkDeletedAndIncompatibleAfterMigration(
             @NonNull SetSchemaResponse setSchemaResponse, @NonNull Set<String> activeMigrators)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index db23a6d..d4e3239 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -332,17 +332,20 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
                     for (int i = 0; i < schemaBundles.size(); i++) {
                         schemas.add(new AppSearchSchema(schemaBundles.get(i)));
@@ -359,7 +362,8 @@
                         }
                         schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers);
                     }
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
+                    // TODO(b/173532925): Implement logging for statsBuilder
                     SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema(
                             packageName,
                             databaseName,
@@ -368,7 +372,8 @@
                             schemasNotDisplayedBySystem,
                             schemasVisibleToPackages,
                             forceOverride,
-                            schemaVersion);
+                            schemaVersion,
+                            /*setSchemaStatsBuilder=*/ null);
                     ++operationSuccessCount;
                     invokeCallbackOnResult(callback,
                             AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
@@ -418,15 +423,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     GetSchemaResponse response =
                             instance.getAppSearchImpl().getSchema(packageName, databaseName);
                     invokeCallbackOnResult(
@@ -450,15 +458,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     List<String> namespaces =
                             instance.getAppSearchImpl().getNamespaces(packageName, databaseName);
                     invokeCallbackOnResult(
@@ -485,20 +496,23 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchBatchResult.Builder<String, Void> resultBuilder =
                             new AppSearchBatchResult.Builder<>();
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     for (int i = 0; i < documentBundles.size(); i++) {
                         GenericDocument document = new GenericDocument(documentBundles.get(i));
                         try {
@@ -571,20 +585,23 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
                             new AppSearchBatchResult.Builder<>();
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     for (int i = 0; i < ids.size(); i++) {
                         String id = ids.get(i);
                         try {
@@ -652,18 +669,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
                             packageName,
                             databaseName,
@@ -718,18 +738,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
 
                     boolean callerHasSystemAccess =
                             instance.getVisibilityStore().doesCallerHaveSystemAccess(packageName);
@@ -783,19 +806,22 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
-            // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
-            // opened it
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
+                    // TODO(b/173532925): Implement logging for statsBuilder
                     SearchResultPage searchResultPage =
-                            instance.getAppSearchImpl().getNextPage(packageName, nextPageToken);
+                            instance.getAppSearchImpl().getNextPage(
+                                    packageName, nextPageToken, /*statsBuilder=*/ null);
                     invokeCallbackOnResult(
                             callback,
                             AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
@@ -812,15 +838,18 @@
             Objects.requireNonNull(userHandle);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     instance.getAppSearchImpl().invalidateNextPageToken(packageName, nextPageToken);
                 } catch (Throwable t) {
                     Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -846,15 +875,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     // we don't need to append the file. The file is always brand new.
                     try (DataOutputStream outputStream = new DataOutputStream(
                             new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
@@ -870,8 +902,11 @@
                                         outputStream, searchResultPage.getResults().get(i)
                                                 .getGenericDocument().getBundle());
                             }
+                            // TODO(b/173532925): Implement logging for statsBuilder
                             searchResultPage = instance.getAppSearchImpl().getNextPage(
-                                    packageName, searchResultPage.getNextPageToken());
+                                    packageName,
+                                    searchResultPage.getNextPageToken(),
+                                    /*statsBuilder=*/ null);
                         }
                     }
                     invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
@@ -895,15 +930,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
 
                     GenericDocument document;
                     ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
@@ -957,15 +995,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
 
                     if (systemUsage
                             && !instance.getVisibilityStore()
@@ -1004,20 +1045,23 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchBatchResult.Builder<String, Void> resultBuilder =
                             new AppSearchBatchResult.Builder<>();
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     for (int i = 0; i < ids.size(); i++) {
                         String id = ids.get(i);
                         try {
@@ -1090,18 +1134,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     instance.getAppSearchImpl().removeByQuery(
                             packageName,
                             databaseName,
@@ -1154,15 +1201,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     StorageInfo storageInfo = instance.getAppSearchImpl()
                             .getStorageInfoForDatabase(packageName, databaseName);
                     Bundle storageInfoBundle = storageInfo.getBundle();
@@ -1184,18 +1234,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
                     ++operationSuccessCount;
                 } catch (Throwable t) {
@@ -1236,7 +1289,6 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
 
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
@@ -1244,12 +1296,18 @@
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    Context targetUserContext = mContext.createContextAsUser(targetUser,
+                            /*flags=*/ 0);
                     instance = mAppSearchUserInstanceManager.getOrCreateUserInstance(
-                            userContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
+                            targetUserContext, targetUser, AppSearchConfig.getInstance(EXECUTOR));
                     ++operationSuccessCount;
                     invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
                 } catch (Throwable t) {
@@ -1278,29 +1336,6 @@
             });
         }
 
-        private void verifyCallingPackage(
-                @NonNull Context userContext,
-                @NonNull UserHandle actualCallingUser,
-                int actualCallingUid,
-                @NonNull String claimedCallingPackage) {
-            Objects.requireNonNull(actualCallingUser);
-            Objects.requireNonNull(claimedCallingPackage);
-
-            int claimedCallingUid = PackageUtil.getPackageUid(
-                    userContext, claimedCallingPackage);
-            if (claimedCallingUid == INVALID_UID) {
-                throw new SecurityException(
-                        "Specified calling package [" + claimedCallingPackage + "] not found");
-            }
-            if (claimedCallingUid != actualCallingUid) {
-                throw new SecurityException(
-                        "Specified calling package ["
-                                + claimedCallingPackage
-                                + "] does not match the calling uid "
-                                + actualCallingUid);
-            }
-        }
-
         /** Invokes the {@link IAppSearchResultCallback} with the result. */
         private void invokeCallbackOnResult(
                 IAppSearchResultCallback callback, AppSearchResult<?> result) {
@@ -1354,33 +1389,72 @@
     /**
      * Helper for dealing with incoming user arguments to system service calls.
      *
-     * @param requestedUser The user which the caller is requesting to execute as.
+     * @param targetUserHandle The user which the caller is requesting to execute as.
      * @param callingUid The actual uid of the caller as determined by Binder.
      * @return the user handle that the call should run as. Will always be a concrete user.
      */
     @NonNull
-    private UserHandle handleIncomingUser(@NonNull UserHandle requestedUser, int callingUid) {
-        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
-        if (callingUser.equals(requestedUser)) {
-            return requestedUser;
+    private UserHandle handleIncomingUser(@NonNull UserHandle targetUserHandle, int callingUid) {
+        UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid);
+        if (callingUserHandle.equals(targetUserHandle)) {
+            return targetUserHandle;
         }
 
         // Duplicates UserController#ensureNotSpecialUser
-        if (requestedUser.getIdentifier() < 0) {
+        if (targetUserHandle.getIdentifier() < 0) {
             throw new IllegalArgumentException(
-                    "Call does not support special user " + requestedUser);
+                    "Call does not support special user " + targetUserHandle);
         }
 
         throw new SecurityException(
-                "Requested user, " + requestedUser + ", is not the same as the calling user, "
-                        + callingUser + ".");
+                "Requested user, " + targetUserHandle + ", is not the same as the calling user, "
+                        + callingUserHandle + ".");
     }
 
     /**
-     * Helper for ensuring instant apps can't make calls to AppSearch.
+     * Verify various aspects of the calling user.
      *
-     * @param userContext Context of the user making the call.
-     * @param packageName Package name of the caller.
+     * @param callingUid Uid of the caller, usually retrieved from Binder for authenticity.
+     * @param claimedCallingPackage Package name the caller claims to be.
+     */
+    private void verifyCaller(int callingUid, @NonNull String claimedCallingPackage) {
+        // Obtain the user where the client is running in. Note that this could be different from
+        // the userHandle where the client wants to run the AppSearch operation in.
+        UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid);
+        Context callingUserContext = mContext.createContextAsUser(callingUserHandle,
+                /*flags=*/ 0);
+
+        verifyCallingPackage(callingUserContext, callingUid, claimedCallingPackage);
+        verifyNotInstantApp(callingUserContext, claimedCallingPackage);
+    }
+
+    /**
+     * Check that the caller's supposed package name matches the uid making the call.
+     *
+     * @throws SecurityException if the package name and uid don't match.
+     */
+    private void verifyCallingPackage(
+            @NonNull Context actualCallingUserContext,
+            int actualCallingUid,
+            @NonNull String claimedCallingPackage) {
+        int claimedCallingUid = PackageUtil.getPackageUid(
+                actualCallingUserContext, claimedCallingPackage);
+        if (claimedCallingUid == INVALID_UID) {
+            throw new SecurityException(
+                    "Specified calling package [" + claimedCallingPackage + "] not found");
+        }
+        if (claimedCallingUid != actualCallingUid) {
+            throw new SecurityException(
+                    "Specified calling package ["
+                            + claimedCallingPackage
+                            + "] does not match the calling uid "
+                            + actualCallingUid);
+        }
+    }
+
+    /**
+     * Ensure instant apps can't make calls to AppSearch.
+     *
      * @throws SecurityException if the caller is an instant app.
      */
     private void verifyNotInstantApp(@NonNull Context userContext, @NonNull String packageName) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 15916cc..324163f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -59,6 +59,7 @@
 import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
 import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
 import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
 
 import com.google.android.icing.IcingSearchEngine;
@@ -393,6 +394,7 @@
      * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
      *     which do not comply with the new schema will be deleted.
      * @param version The overall version number of the request.
+     * @param setSchemaStatsBuilder Builder for {@link SetSchemaStats} to hold stats for setSchema
      * @return The response contains deleted schema types and incompatible schema types of this
      *     call.
      * @throws AppSearchException On IcingSearchEngine error. If the status code is
@@ -408,7 +410,8 @@
             @NonNull List<String> schemasNotDisplayedBySystem,
             @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages,
             boolean forceOverride,
-            int version)
+            int version,
+            @Nullable SetSchemaStats.Builder setSchemaStatsBuilder)
             throws AppSearchException {
         mReadWriteLock.writeLock().lock();
         try {
@@ -438,6 +441,12 @@
             mLogUtil.piiTrace(
                     "setSchema, response", setSchemaResultProto.getStatus(), setSchemaResultProto);
 
+            if (setSchemaStatsBuilder != null) {
+                setSchemaStatsBuilder.setStatusCode(
+                        statusProtoToResultCode(setSchemaResultProto.getStatus()));
+                AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto, setSchemaStatsBuilder);
+            }
+
             // Determine whether it succeeded.
             try {
                 checkSuccess(setSchemaResultProto.getStatus());
@@ -1127,8 +1136,13 @@
      * @throws AppSearchException on IcingSearchEngine error or if can't advance on nextPageToken.
      */
     @NonNull
-    public SearchResultPage getNextPage(@NonNull String packageName, long nextPageToken)
+    public SearchResultPage getNextPage(
+            @NonNull String packageName,
+            long nextPageToken,
+            @Nullable SearchStats.Builder statsBuilder)
             throws AppSearchException {
+        long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+
         mReadWriteLock.readLock().lock();
         try {
             throwIfClosedLocked();
@@ -1137,6 +1151,13 @@
             checkNextPageToken(packageName, nextPageToken);
             SearchResultProto searchResultProto =
                     mIcingSearchEngineLocked.getNextPage(nextPageToken);
+
+            if (statsBuilder != null) {
+                statsBuilder.setStatusCode(statusProtoToResultCode(searchResultProto.getStatus()));
+                AppSearchLoggerHelper.copyNativeStats(
+                        searchResultProto.getQueryStats(), statsBuilder);
+            }
+
             mLogUtil.piiTrace(
                     "getNextPage, response",
                     searchResultProto.getResultsCount(),
@@ -1152,9 +1173,22 @@
                     mNextPageTokensLocked.get(packageName).remove(nextPageToken);
                 }
             }
-            return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
+            long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime();
+            SearchResultPage resultPage =
+                    rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
+            if (statsBuilder != null) {
+                statsBuilder.setRewriteSearchResultLatencyMillis(
+                        (int)
+                                (SystemClock.elapsedRealtime()
+                                        - rewriteSearchResultLatencyStartMillis));
+            }
+            return resultPage;
         } finally {
             mReadWriteLock.readLock().unlock();
+            if (statsBuilder != null) {
+                statsBuilder.setTotalLatencyMillis(
+                        (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis));
+            }
         }
     }
 
@@ -1334,7 +1368,7 @@
                         statusProtoToResultCode(deleteResultProto.getStatus()));
                 // TODO(b/187206766) also log query stats here once IcingLib returns it
                 AppSearchLoggerHelper.copyNativeStats(
-                        deleteResultProto.getDeleteStats(), removeStatsBuilder);
+                        deleteResultProto.getDeleteByQueryStats(), removeStatsBuilder);
             }
 
             // It seems that the caller wants to get success if the data matching the query is
@@ -1343,7 +1377,8 @@
                     deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
 
             // Update derived maps
-            int numDocumentsDeleted = deleteResultProto.getDeleteStats().getNumDocumentsDeleted();
+            int numDocumentsDeleted =
+                    deleteResultProto.getDeleteByQueryStats().getNumDocumentsDeleted();
             updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted);
         } finally {
             mReadWriteLock.writeLock().unlock();
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
index 98cedc7..1f7d44e 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
@@ -24,6 +24,7 @@
 import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
 import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
 
 /**
  * An interface for implementing client-defined logging AppSearch operations stats.
@@ -54,5 +55,8 @@
     /** Logs {@link OptimizeStats} */
     void logStats(@NonNull OptimizeStats stats);
 
+    /** Logs {@link SetSchemaStats} */
+    void logStats(@NonNull SetSchemaStats stats);
+
     // TODO(b/173532925) Add remaining logStats once we add all the stats.
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index cd653e5..c19ba14 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -23,12 +23,15 @@
 import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
 import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
 
+import com.google.android.icing.proto.DeleteByQueryStatsProto;
 import com.google.android.icing.proto.DeleteStatsProto;
 import com.google.android.icing.proto.InitializeStatsProto;
 import com.google.android.icing.proto.OptimizeStatsProto;
 import com.google.android.icing.proto.PutDocumentStatsProto;
 import com.google.android.icing.proto.QueryStatsProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
 
 import java.util.Objects;
 
@@ -142,6 +145,26 @@
     }
 
     /**
+     * Copies native DeleteByQuery stats to builder.
+     *
+     * @param fromNativeStats Stats copied from.
+     * @param toStatsBuilder Stats copied to.
+     */
+    static void copyNativeStats(
+            @NonNull DeleteByQueryStatsProto fromNativeStats,
+            @NonNull RemoveStats.Builder toStatsBuilder) {
+        Objects.requireNonNull(fromNativeStats);
+        Objects.requireNonNull(toStatsBuilder);
+
+        @SuppressWarnings("deprecation")
+        int deleteType = DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY.getNumber();
+        toStatsBuilder
+                .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+                .setDeleteType(deleteType)
+                .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted());
+    }
+
+    /**
      * Copies native {@link OptimizeStatsProto} to builder.
      *
      * @param fromNativeStats Stats copied from.
@@ -164,4 +187,25 @@
                 .setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter())
                 .setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs());
     }
+
+    /*
+     * Copy SetSchema result stats to builder.
+     *
+     * @param fromProto Stats copied from.
+     * @param toStatsBuilder Stats copied to.
+     */
+    static void copyNativeStats(
+            @NonNull SetSchemaResultProto fromProto,
+            @NonNull SetSchemaStats.Builder toStatsBuilder) {
+        Objects.requireNonNull(fromProto);
+        Objects.requireNonNull(toStatsBuilder);
+        toStatsBuilder
+                .setNewTypeCount(fromProto.getNewSchemaTypesCount())
+                .setDeletedTypeCount(fromProto.getDeletedSchemaTypesCount())
+                .setCompatibleTypeChangeCount(fromProto.getFullyCompatibleChangedSchemaTypesCount())
+                .setIndexIncompatibleTypeChangeCount(
+                        fromProto.getIndexIncompatibleChangedSchemaTypesCount())
+                .setBackwardsIncompatibleTypeChangeCount(
+                        fromProto.getIncompatibleSchemaTypesCount());
+    }
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java
index d7904f3..75ae2d0a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java
@@ -40,6 +40,7 @@
                 VISIBILITY_SCOPE_LOCAL,
                 // Searches the global documents. Including platform surfaceable and 3p-access.
                 VISIBILITY_SCOPE_GLOBAL,
+                VISIBILITY_SCOPE_UNKNOWN,
                 // TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform
                 //  surfaceable from 3p access(right both of them are categorized as
                 //  VISIBILITY_SCOPE_GLOBAL)
@@ -51,6 +52,7 @@
     public static final int VISIBILITY_SCOPE_LOCAL = 1;
     // Searches the global documents. Including platform surfaceable and 3p-access.
     public static final int VISIBILITY_SCOPE_GLOBAL = 2;
+    public static final int VISIBILITY_SCOPE_UNKNOWN = 3;
 
     // TODO(b/173532925): Add a field searchType to indicate where the search is used(normal
     //  query vs in removeByQuery vs during migration)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
index 9d789a8..3e5a80f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
@@ -47,9 +47,6 @@
 
     private final int mTotalLatencyMillis;
 
-    /** Overall time used for the native function call. */
-    private final int mNativeLatencyMillis;
-
     /** Number of newly added schema types. */
     private final int mNewTypeCount;
 
@@ -72,7 +69,6 @@
         mStatusCode = builder.mStatusCode;
         mSchemaMigrationStats = builder.mSchemaMigrationStats;
         mTotalLatencyMillis = builder.mTotalLatencyMillis;
-        mNativeLatencyMillis = builder.mNativeLatencyMillis;
         mNewTypeCount = builder.mNewTypeCount;
         mDeletedTypeCount = builder.mDeletedTypeCount;
         mCompatibleTypeChangeCount = builder.mCompatibleTypeChangeCount;
@@ -112,11 +108,6 @@
         return mTotalLatencyMillis;
     }
 
-    /** Returns overall time used for the native function call. */
-    public int getNativeLatencyMillis() {
-        return mNativeLatencyMillis;
-    }
-
     /** Returns number of newly added schema types. */
     public int getNewTypeCount() {
         return mNewTypeCount;
@@ -159,7 +150,6 @@
         @AppSearchResult.ResultCode int mStatusCode;
         @Nullable SchemaMigrationStats mSchemaMigrationStats;
         int mTotalLatencyMillis;
-        int mNativeLatencyMillis;
         int mNewTypeCount;
         int mDeletedTypeCount;
         int mCompatibleTypeChangeCount;
@@ -193,13 +183,6 @@
             return this;
         }
 
-        /** Sets native latency in milliseconds. */
-        @NonNull
-        public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
-            mNativeLatencyMillis = nativeLatencyMillis;
-            return this;
-        }
-
         /** Sets number of new types. */
         @NonNull
         public Builder setNewTypeCount(int newTypeCount) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index fdf6a00..4c29ece 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -36,6 +36,7 @@
 import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
 import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
 import com.android.server.appsearch.util.PackageUtil;
 
 import java.io.UnsupportedEncodingException;
@@ -180,6 +181,11 @@
         }
     }
 
+    @Override
+    public void logStats(@NonNull SetSchemaStats stats) {
+        // TODO(b/173532925): Log stats
+    }
+
     /**
      * Removes cached UID for package.
      *
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
index ce142d6..c4d1016 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
@@ -126,7 +126,8 @@
                     /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                     /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                     /*forceOverride=*/ false,
-                    /*version=*/ SCHEMA_VERSION);
+                    /*version=*/ SCHEMA_VERSION,
+                    /*setSchemaStatsBuilder=*/ null);
         }
 
         // Populate visibility settings set
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index a81d7d80..4db8355 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-Ie04f1ecc033faae8085afcb51eb9e40a298998d5
+bd53b062816070b64feb992c2bf58f3afa3d420e
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index 5407cb4..f78d98a 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -28,6 +28,7 @@
         "framework",
         "framework-appsearch",
         "guava",
+        "service-appsearch",
         "truth-prebuilt",
     ],
     visibility: [
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
index ec9a42ea..4d8e8e9 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.appsearch.AppSearchBatchResult;
 import android.app.appsearch.AppSearchSessionShim;
 import android.app.appsearch.GenericDocument;
@@ -26,12 +28,66 @@
 import android.app.appsearch.SearchResult;
 import android.app.appsearch.SearchResultsShim;
 
+import com.android.server.appsearch.external.localstorage.AppSearchLogger;
+import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
+import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
+import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
+import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Future;
 
 public class AppSearchTestUtils {
+    // Non-thread-safe logger implementation for testing
+    public static class TestLogger implements AppSearchLogger {
+        @Nullable public CallStats mCallStats;
+        @Nullable public PutDocumentStats mPutDocumentStats;
+        @Nullable public InitializeStats mInitializeStats;
+        @Nullable public SearchStats mSearchStats;
+        @Nullable public RemoveStats mRemoveStats;
+        @Nullable public OptimizeStats mOptimizeStats;
+        @Nullable public SetSchemaStats mSetSchemaStats;
+
+        @Override
+        public void logStats(@NonNull CallStats stats) {
+            mCallStats = stats;
+        }
+
+        @Override
+        public void logStats(@NonNull PutDocumentStats stats) {
+            mPutDocumentStats = stats;
+        }
+
+        @Override
+        public void logStats(@NonNull InitializeStats stats) {
+            mInitializeStats = stats;
+        }
+
+        @Override
+        public void logStats(@NonNull SearchStats stats) {
+            mSearchStats = stats;
+        }
+
+        @Override
+        public void logStats(@NonNull RemoveStats stats) {
+            mRemoveStats = stats;
+        }
+
+        @Override
+        public void logStats(@NonNull OptimizeStats stats) {
+            mOptimizeStats = stats;
+        }
+
+        @Override
+        public void logStats(@NonNull SetSchemaStats stats) {
+            mSetSchemaStats = stats;
+        }
+    }
 
     public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
             Future<AppSearchBatchResult<K, V>> future) throws Exception {
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..8c8d2bf
--- /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 float DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01f;
+    /** @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 float DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5f;
+    /** @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/framework/java/com/android/server/AppStateTracker.java b/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java
index b0b9abc..fc27a79 100644
--- a/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java
+++ b/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java
@@ -25,19 +25,25 @@
     String TAG = "AppStateTracker";
 
     /**
-     * Register a {@link ServiceStateListener} to listen for forced-app-standby changes that should
-     * affect services.
+     * Register a {@link BackgroundRestrictedAppListener} to listen for background restricted mode
+     * changes that should affect services etc.
      */
-    void addServiceStateListener(@NonNull ServiceStateListener listener);
+    void addBackgroundRestrictedAppListener(@NonNull BackgroundRestrictedAppListener listener);
 
     /**
-     * A listener to listen to forced-app-standby changes that should affect services.
+     * @return {code true} if the given UID/package has been in background restricted mode,
+     * it does NOT include the case where the "force app background restricted" is enabled.
      */
-    interface ServiceStateListener {
+    boolean isAppBackgroundRestricted(int uid, @NonNull String packageName);
+
+    /**
+     * A listener to listen to background restricted mode changes that should affect services etc.
+     */
+    interface BackgroundRestrictedAppListener {
         /**
-         * Called when an app goes into forced app standby and its foreground
-         * services need to be removed from that state.
+         * Called when an app goes in/out of background restricted mode.
          */
-        void stopForegroundServicesForUidPackage(int uid, String packageName);
+        void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+                boolean restricted);
     }
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index c332a59..d0a155d 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -60,8 +60,10 @@
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Class to keep track of the information related to "force app standby", which includes:
@@ -160,16 +162,34 @@
     @GuardedBy("mLock")
     boolean mForcedAppStandbyEnabled;
 
+    /**
+     * A lock-free set of (uid, packageName) pairs in background restricted mode.
+     *
+     * <p>
+     * It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with
+     * the {@link #mForcedAppStandbyEnabled} - mutations on them would result in copy-on-write.
+     * </p>
+     */
+    volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet();
+
     @Override
-    public void addServiceStateListener(@NonNull ServiceStateListener listener) {
+    public void addBackgroundRestrictedAppListener(
+            @NonNull BackgroundRestrictedAppListener listener) {
         addListener(new Listener() {
             @Override
-            public void stopForegroundServicesForUidPackage(int uid, String packageName) {
-                listener.stopForegroundServicesForUidPackage(uid, packageName);
+            public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+                    boolean restricted) {
+                listener.updateBackgroundRestrictedForUidPackage(uid, packageName, restricted);
             }
         });
     }
 
+    @Override
+    public boolean isAppBackgroundRestricted(int uid, @NonNull String packageName) {
+        final Set<Pair<Integer, String>> bgRestrictedUidPkgs = mBackgroundRestrictedUidPackages;
+        return bgRestrictedUidPkgs.contains(Pair.create(uid, packageName));
+    }
+
     interface Stats {
         int UID_FG_STATE_CHANGED = 0;
         int UID_ACTIVE_STATE_CHANGED = 1;
@@ -233,6 +253,7 @@
                         return;
                     }
                     mForcedAppStandbyEnabled = enabled;
+                    updateBackgroundRestrictedUidPackagesLocked();
                     if (DEBUG) {
                         Slog.d(TAG, "Forced app standby feature flag changed: "
                                 + mForcedAppStandbyEnabled);
@@ -277,7 +298,11 @@
             if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
                 Slog.v(TAG, "Package " + packageName + "/" + uid
                         + " toggled into fg service restriction");
-                stopForegroundServicesForUidPackage(uid, packageName);
+                updateBackgroundRestrictedForUidPackage(uid, packageName, true);
+            } else {
+                Slog.v(TAG, "Package " + packageName + "/" + uid
+                        + " toggled out of fg service restriction");
+                updateBackgroundRestrictedForUidPackage(uid, packageName, false);
             }
         }
 
@@ -366,10 +391,10 @@
         }
 
         /**
-         * Called when an app goes into forced app standby and its foreground
-         * services need to be removed from that state.
+         * Called when an app goes in/out of background restricted mode.
          */
-        public void stopForegroundServicesForUidPackage(int uid, String packageName) {
+        public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+                boolean restricted) {
         }
 
         /**
@@ -438,9 +463,12 @@
                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                         // No need to notify for state change as all the alarms and jobs should be
                         // removed too.
-                        mExemptedBucketPackages.remove(userId, pkgName);
-                        mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
-                        mActiveUids.delete(uid);
+                        synchronized (mLock) {
+                            mExemptedBucketPackages.remove(userId, pkgName);
+                            mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
+                            updateBackgroundRestrictedUidPackagesLocked();
+                            mActiveUids.delete(uid);
+                        }
                     }
                     break;
             }
@@ -580,6 +608,28 @@
                 }
             }
         }
+        updateBackgroundRestrictedUidPackagesLocked();
+    }
+
+    /**
+     * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
+     * {@link #mRunAnyRestrictedPackages} or {@link #mForcedAppStandbyEnabled}.
+     */
+    @GuardedBy("mLock")
+    private void updateBackgroundRestrictedUidPackagesLocked() {
+        if (!mForcedAppStandbyEnabled) {
+            mBackgroundRestrictedUidPackages = Collections.emptySet();
+            return;
+        }
+        if (mForceAllAppsStandby) {
+            mBackgroundRestrictedUidPackages = null;
+            return;
+        }
+        Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
+        for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
+            fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
+        }
+        mBackgroundRestrictedUidPackages = Collections.unmodifiableSet(fasUidPkgs);
     }
 
     private void updateForceAllAppStandbyState() {
@@ -645,6 +695,7 @@
         } else {
             mRunAnyRestrictedPackages.removeAt(index);
         }
+        updateBackgroundRestrictedUidPackagesLocked();
         return true;
     }
 
@@ -966,6 +1017,7 @@
                     mRunAnyRestrictedPackages.removeAt(i);
                 }
             }
+            updateBackgroundRestrictedUidPackagesLocked();
             cleanUpArrayForUser(mActiveUids, removedUserId);
             mExemptedBucketPackages.remove(removedUserId);
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 03465fd..19aed49 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -3941,6 +3941,10 @@
         if (idleUntil) {
             mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+        } else if (mState == STATE_LOCATING) {
+            // Use setExact so we don't keep the GPS active for too long.
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
         } else {
             if (mConstants.USE_WINDOW_ALARMS) {
                 mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
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 f0745f3..26237c4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -40,6 +40,7 @@
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -50,6 +51,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
@@ -66,6 +68,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.DeviceConfig;
+import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -106,6 +109,7 @@
 import com.android.server.job.controllers.RestrictingController;
 import com.android.server.job.controllers.StateController;
 import com.android.server.job.controllers.StorageController;
+import com.android.server.job.controllers.TareController;
 import com.android.server.job.controllers.TimeController;
 import com.android.server.job.restrictions.JobRestriction;
 import com.android.server.job.restrictions.ThermalStatusRestriction;
@@ -250,6 +254,8 @@
     private final DeviceIdleJobsController mDeviceIdleJobsController;
     /** Needed to get remaining quota time. */
     private final QuotaController mQuotaController;
+    /** Needed to get max execution time and expedited-job allowance. */
+    private final TareController mTareController;
     /**
      * List of restrictions.
      * Note: do not add to or remove from this list at runtime except in the constructor, because we
@@ -344,15 +350,41 @@
     // (ScheduledJobStateChanged and JobStatusDumpProto).
     public static final int RESTRICTED_INDEX = 5;
 
-    private class ConstantsObserver implements DeviceConfig.OnPropertiesChangedListener {
+    private class ConstantsObserver extends ContentObserver
+            implements DeviceConfig.OnPropertiesChangedListener {
+        private final ContentResolver mContentResolver;
+
+        ConstantsObserver(Handler handler, Context context) {
+            super(handler);
+            mContentResolver = context.getContentResolver();
+        }
+
         public void start() {
             DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
                     JobSchedulerBackgroundThread.getExecutor(), this);
+            mContentResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
             // Load all the constants.
+            synchronized (mLock) {
+                mConstants.updateSettingsConstantsLocked(mContentResolver);
+            }
             onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
         }
 
         @Override
+        public void onChange(boolean selfChange) {
+            synchronized (mLock) {
+                if (mConstants.updateSettingsConstantsLocked(mContentResolver)) {
+                    for (int controller = 0; controller < mControllers.size(); controller++) {
+                        final StateController sc = mControllers.get(controller);
+                        sc.onConstantsUpdatedLocked();
+                    }
+                    onControllerStateChanged(null);
+                }
+            }
+        }
+
+        @Override
         public void onPropertiesChanged(DeviceConfig.Properties properties) {
             boolean apiQuotaScheduleUpdated = false;
             boolean concurrencyUpdated = false;
@@ -482,6 +514,7 @@
         public static final long DEFAULT_RUNTIME_MIN_GUARANTEE_MS = 10 * MINUTE_IN_MILLIS;
         @VisibleForTesting
         public static final long DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS = 3 * MINUTE_IN_MILLIS;
+        private static final boolean DEFAULT_USE_TARE_POLICY = false;
 
         /**
          * Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
@@ -559,6 +592,11 @@
          */
         public long RUNTIME_MIN_EJ_GUARANTEE_MS = DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS;
 
+        /**
+         * If true, use TARE policy for job limiting. If false, use quotas.
+         */
+        public boolean USE_TARE_POLICY = DEFAULT_USE_TARE_POLICY;
+
         private void updateBatchingConstantsLocked() {
             MIN_READY_NON_ACTIVE_JOBS_COUNT = DeviceConfig.getInt(
                     DeviceConfig.NAMESPACE_JOB_SCHEDULER,
@@ -637,6 +675,17 @@
                             DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS));
         }
 
+        private boolean updateSettingsConstantsLocked(ContentResolver contentResolver) {
+            boolean changed = false;
+            final boolean isTareEnabled = Settings.Global.getInt(contentResolver,
+                    Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
+            if (USE_TARE_POLICY != isTareEnabled) {
+                USE_TARE_POLICY = isTareEnabled;
+                changed = true;
+            }
+            return changed;
+        }
+
         void dump(IndentingPrintWriter pw) {
             pw.println("Settings:");
             pw.increaseIndent();
@@ -665,6 +714,8 @@
             pw.print(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
                     .println();
 
+            pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY).println();
+
             pw.decreaseIndent();
         }
 
@@ -1130,9 +1181,12 @@
             JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
 
             // Return failure early if expedited job quota used up.
-            if (jobStatus.isRequestedExpeditedJob()
-                    && !mQuotaController.isWithinEJQuotaLocked(jobStatus)) {
-                return JobScheduler.RESULT_FAILURE;
+            if (jobStatus.isRequestedExpeditedJob()) {
+                if ((mConstants.USE_TARE_POLICY && !mTareController.canScheduleEJ(jobStatus))
+                        || (!mConstants.USE_TARE_POLICY
+                        && !mQuotaController.isWithinEJQuotaLocked(jobStatus))) {
+                    return JobScheduler.RESULT_FAILURE;
+                }
             }
 
             // Give exemption if the source is in the foreground just now.
@@ -1474,7 +1528,7 @@
 
         mHandler = new JobHandler(context.getMainLooper());
         mConstants = new Constants();
-        mConstantsObserver = new ConstantsObserver();
+        mConstantsObserver = new ConstantsObserver(mHandler, context);
         mJobSchedulerStub = new JobSchedulerStub();
 
         mConcurrencyManager = new JobConcurrencyManager(this);
@@ -1519,6 +1573,9 @@
                 new QuotaController(this, backgroundJobsController, connectivityController);
         mControllers.add(mQuotaController);
         mControllers.add(new ComponentController(this));
+        mTareController =
+                new TareController(this, backgroundJobsController, connectivityController);
+        mControllers.add(mTareController);
 
         mRestrictiveControllers = new ArrayList<>();
         mRestrictiveControllers.add(mBatteryController);
@@ -2560,7 +2617,9 @@
     public long getMaxJobExecutionTimeMs(JobStatus job) {
         synchronized (mLock) {
             return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
-                    mQuotaController.getMaxJobExecutionTimeMsLocked(job));
+                    mConstants.USE_TARE_POLICY
+                            ? mTareController.getMaxJobExecutionTimeMsLocked(job)
+                            : mQuotaController.getMaxJobExecutionTimeMsLocked(job));
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 986b2d9..5bdee5e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -54,6 +54,9 @@
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.job.controllers.JobStatus;
+import com.android.server.tare.EconomicPolicy;
+import com.android.server.tare.EconomyManagerInternal;
+import com.android.server.tare.JobSchedulerEconomicPolicy;
 
 /**
  * Handles client binding and lifecycle of a job. Jobs execute one at a time on an instance of this
@@ -107,6 +110,7 @@
     private final Context mContext;
     private final Object mLock;
     private final IBatteryStats mBatteryStats;
+    private final EconomyManagerInternal mEconomyManagerInternal;
     private final JobPackageTracker mJobPackageTracker;
     private final PowerManager mPowerManager;
     private PowerManager.WakeLock mWakeLock;
@@ -211,6 +215,7 @@
         mLock = service.getLock();
         mService = service;
         mBatteryStats = batteryStats;
+        mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
         mJobPackageTracker = tracker;
         mCallbackHandler = new JobServiceHandler(looper);
         mJobConcurrencyManager = concurrencyManager;
@@ -288,6 +293,11 @@
             mWakeLock.setReferenceCounted(false);
             mWakeLock.acquire();
 
+            // Note the start when we try to bind so that the app is charged for some processing
+            // even if binding fails.
+            mEconomyManagerInternal.noteInstantaneousEvent(
+                    job.getSourceUserId(), job.getSourcePackageName(),
+                    getStartActionId(job), String.valueOf(job.getJobId()));
             mVerb = VERB_BINDING;
             scheduleOpTimeOutLocked();
             final Intent intent = new Intent().setComponent(job.getServiceComponent());
@@ -350,6 +360,9 @@
             } catch (RemoteException e) {
                 // Whatever.
             }
+            mEconomyManagerInternal.noteOngoingEventStarted(
+                    job.getSourceUserId(), job.getSourcePackageName(),
+                    getRunningActionId(job), String.valueOf(job.getJobId()));
             final String jobPackage = job.getSourcePackageName();
             final int jobUserId = job.getSourceUserId();
             UsageStatsManagerInternal usageStats =
@@ -363,6 +376,22 @@
         }
     }
 
+    @EconomicPolicy.AppAction
+    private static int getStartActionId(@NonNull JobStatus job) {
+        if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) {
+            return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START;
+        }
+        return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START;
+    }
+
+    @EconomicPolicy.AppAction
+    private static int getRunningActionId(@NonNull JobStatus job) {
+        if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) {
+            return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING;
+        }
+        return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING;
+    }
+
     /**
      * Used externally to query the running job. Will return null if there is no job running.
      */
@@ -531,6 +560,42 @@
         }
     }
 
+    @Override
+    public void onBindingDied(ComponentName name) {
+        synchronized (mLock) {
+            if (mRunningJob == null) {
+                Slog.e(TAG, "Binding died for " + name.getPackageName()
+                        + " but no running job on this context");
+            } else if (mRunningJob.getServiceComponent().equals(name)) {
+                Slog.e(TAG, "Binding died for "
+                        + mRunningJob.getSourceUserId() + ":" + name.getPackageName());
+            } else {
+                Slog.e(TAG, "Binding died for " + name.getPackageName()
+                        + " but context is running a different job");
+            }
+            closeAndCleanupJobLocked(true /* needsReschedule */, "binding died");
+        }
+    }
+
+    @Override
+    public void onNullBinding(ComponentName name) {
+        synchronized (mLock) {
+            if (mRunningJob == null) {
+                Slog.wtf(TAG, "Got null binding for " + name.getPackageName()
+                        + " but no running job on this context");
+            } else if (mRunningJob.getServiceComponent().equals(name)) {
+                Slog.wtf(TAG, "Got null binding for "
+                        + mRunningJob.getSourceUserId() + ":" + name.getPackageName());
+            } else {
+                Slog.wtf(TAG, "Got null binding for " + name.getPackageName()
+                        + " but context is running a different job");
+            }
+            // Don't reschedule the job since returning a null binding is an explicit choice by the
+            // app which breaks things.
+            closeAndCleanupJobLocked(false /* needsReschedule */, "null binding");
+        }
+    }
+
     /**
      * This class is reused across different clients, and passes itself in as a callback. Check
      * whether the client exercising the callback is the client we expect.
@@ -946,6 +1011,15 @@
         } catch (RemoteException e) {
             // Whatever.
         }
+        mEconomyManagerInternal.noteOngoingEventStopped(
+                mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(),
+                getRunningActionId(mRunningJob), String.valueOf(mRunningJob.getJobId()));
+        if (mParams.getStopReason() == JobParameters.STOP_REASON_TIMEOUT) {
+            mEconomyManagerInternal.noteInstantaneousEvent(
+                    mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(),
+                    JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
+                    String.valueOf(mRunningJob.getJobId()));
+        }
         if (mWakeLock != null) {
             mWakeLock.release();
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 7a28407..d1afc80 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -41,13 +41,13 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SystemConfigFileCommitEventLogger;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.BitUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
@@ -57,13 +57,12 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -133,7 +132,7 @@
     @VisibleForTesting
     public static JobStore initAndGetForTesting(Context context, File dataDir) {
         JobStore jobStoreUnderTest = new JobStore(context, new Object(), dataDir);
-        jobStoreUnderTest.clear();
+        jobStoreUnderTest.clearForTesting();
         return jobStoreUnderTest;
     }
 
@@ -222,6 +221,14 @@
         return replaced;
     }
 
+    /**
+     * The same as above but does not schedule writing. This makes perf benchmarks more stable.
+     */
+    @VisibleForTesting
+    public void addForTesting(JobStatus jobStatus) {
+        mJobSet.add(jobStatus);
+    }
+
     boolean containsJob(JobStatus jobStatus) {
         return mJobSet.contains(jobStatus);
     }
@@ -273,6 +280,14 @@
     }
 
     /**
+     * The same as above but does not schedule writing. This makes perf benchmarks more stable.
+     */
+    @VisibleForTesting
+    public void clearForTesting() {
+        mJobSet.clear();
+    }
+
+    /**
      * @param userHandle User for whom we are querying the list of jobs.
      * @return A list of all the jobs scheduled for the provided user. Never null.
      */
@@ -469,11 +484,9 @@
             int numJobs = 0;
             int numSystemJobs = 0;
             int numSyncJobs = 0;
-            try {
-                mEventLogger.setStartTime(SystemClock.uptimeMillis());
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(baos, StandardCharsets.UTF_8.name());
+            mEventLogger.setStartTime(SystemClock.uptimeMillis());
+            try (FileOutputStream fos = mJobsFile.startWrite()) {
+                TypedXmlSerializer out = Xml.resolveSerializer(fos);
                 out.startDocument(null, true);
                 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
@@ -502,9 +515,6 @@
                 out.endTag(null, "job-info");
                 out.endDocument();
 
-                // Write out to disk in one fell swoop.
-                FileOutputStream fos = mJobsFile.startWrite();
-                fos.write(baos.toByteArray());
                 mJobsFile.finishWrite(fos);
             } catch (IOException e) {
                 if (DEBUG) {
@@ -703,9 +713,8 @@
             int numJobs = 0;
             int numSystemJobs = 0;
             int numSyncJobs = 0;
-            try {
-                List<JobStatus> jobs;
-                FileInputStream fis = mJobsFile.openRead();
+            List<JobStatus> jobs;
+            try (FileInputStream fis = mJobsFile.openRead()) {
                 synchronized (mLock) {
                     jobs = readJobMapImpl(fis, rtcGood);
                     if (jobs != null) {
@@ -726,7 +735,6 @@
                         }
                     }
                 }
-                fis.close();
             } catch (FileNotFoundException e) {
                 if (DEBUG) {
                     Slog.d(TAG, "Could not find jobs file, probably there was nothing to load.");
@@ -743,10 +751,9 @@
             Slog.i(TAG, "Read " + numJobs + " jobs");
         }
 
-        private List<JobStatus> readJobMapImpl(FileInputStream fis, boolean rtcIsGood)
+        private List<JobStatus> readJobMapImpl(InputStream fis, boolean rtcIsGood)
                 throws XmlPullParserException, IOException {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(fis, StandardCharsets.UTF_8.name());
+            XmlPullParser parser = Xml.resolvePullParser(fis);
 
             int eventType = parser.getEventType();
             while (eventType != XmlPullParser.START_TAG &&
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 321c0b3..607ed3c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -661,7 +661,8 @@
             NetworkCapabilities capabilities, Constants constants) {
         // A restricted job that's out of quota MUST use an unmetered network.
         if (jobStatus.getEffectiveStandbyBucket() == RESTRICTED_INDEX
-                && !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
+                && (!jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)
+                || !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_TARE_WEALTH))) {
             final NetworkCapabilities.Builder builder =
                     copyCapabilities(jobStatus.getJob().getRequiredNetwork());
             builder.addCapability(NET_CAPABILITY_NOT_METERED);
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 844a480..3801885 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
@@ -1141,7 +1141,7 @@
      * treated as an expedited job.
      */
     public boolean shouldTreatAsExpeditedJob() {
-        return mExpeditedQuotaApproved && isRequestedExpeditedJob();
+        return mExpeditedQuotaApproved && mExpeditedTareApproved && isRequestedExpeditedJob();
     }
 
     /**
@@ -1564,7 +1564,8 @@
         // sessions (exempt from dynamic restrictions), we need the additional check to ensure
         // that NEVER jobs don't run.
         // TODO: cleanup quota and standby bucket management so we don't need the additional checks
-        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied && !shouldTreatAsExpeditedJob())
+        if (((!mReadyWithinQuota || !mReadyTareWealth)
+                && !mReadyDynamicSatisfied && !shouldTreatAsExpeditedJob())
                 || getEffectiveStandbyBucket() == NEVER_INDEX) {
             return false;
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 36afac8..4ea46eb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -372,6 +372,9 @@
     private final BackgroundJobsController mBackgroundJobsController;
     private final ConnectivityController mConnectivityController;
 
+    @GuardedBy("mLock")
+    private boolean mIsEnabled;
+
     /** How much time each app will have to run jobs within their standby bucket window. */
     private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
 
@@ -590,6 +593,7 @@
         mQcConstants = new QcConstants();
         mBackgroundJobsController = backgroundJobsController;
         mConnectivityController = connectivityController;
+        mIsEnabled = !mConstants.USE_TARE_POLICY;
 
         // Set up the app standby bucketing tracker
         AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
@@ -837,6 +841,9 @@
     /** @return true if the job is within expedited job quota. */
     @GuardedBy("mLock")
     public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) {
+        if (!mIsEnabled) {
+            return true;
+        }
         if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) {
             return true;
         }
@@ -884,6 +891,9 @@
 
     @VisibleForTesting
     boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
+        if (!mIsEnabled) {
+            return true;
+        }
         final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
         // A job is within quota if one of the following is true:
         //   1. it was started while the app was in the TOP state
@@ -910,6 +920,9 @@
     @GuardedBy("mLock")
     boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
             final int standbyBucket) {
+        if (!mIsEnabled) {
+            return true;
+        }
         if (standbyBucket == NEVER_INDEX) return false;
 
         if (isQuotaFreeLocked(standbyBucket)) return true;
@@ -2980,7 +2993,8 @@
 
     @Override
     public void onConstantsUpdatedLocked() {
-        if (mQcConstants.mShouldReevaluateConstraints) {
+        if (mQcConstants.mShouldReevaluateConstraints || mIsEnabled == mConstants.USE_TARE_POLICY) {
+            mIsEnabled = !mConstants.USE_TARE_POLICY;
             // Update job bookkeeping out of band.
             JobSchedulerBackgroundThread.getHandler().post(() -> {
                 synchronized (mLock) {
@@ -4120,6 +4134,7 @@
     @Override
     public void dumpControllerStateLocked(final IndentingPrintWriter pw,
             final Predicate<JobStatus> predicate) {
+        pw.println("Is enabled: " + mIsEnabled);
         pw.println("Is charging: " + mChargeTracker.isChargingLocked());
         pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
         pw.println();
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
index 401646d..be3a3ee 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
@@ -27,6 +27,7 @@
 import android.util.SparseArrayMap;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.tare.EconomyManagerInternal;
@@ -170,6 +171,7 @@
         mBackgroundJobsController = backgroundJobsController;
         mConnectivityController = connectivityController;
         mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
+        mIsEnabled = mConstants.USE_TARE_POLICY;
     }
 
     @Override
@@ -237,6 +239,32 @@
         }
     }
 
+    @Override
+    @GuardedBy("mLock")
+    public void onConstantsUpdatedLocked() {
+        if (mIsEnabled != mConstants.USE_TARE_POLICY) {
+            mIsEnabled = mConstants.USE_TARE_POLICY;
+            // Update job bookkeeping out of band.
+            JobSchedulerBackgroundThread.getHandler().post(() -> {
+                synchronized (mLock) {
+                    final long nowElapsed = sElapsedRealtimeClock.millis();
+                    mService.getJobStore().forEachJob((jobStatus) -> {
+                        if (!mIsEnabled) {
+                            jobStatus.setTareWealthConstraintSatisfied(nowElapsed, true);
+                            setExpeditedTareApproved(jobStatus, nowElapsed, true);
+                        } else {
+                            jobStatus.setTareWealthConstraintSatisfied(
+                                    nowElapsed, hasEnoughWealthLocked(jobStatus));
+                            setExpeditedTareApproved(jobStatus, nowElapsed,
+                                    jobStatus.isRequestedExpeditedJob()
+                                            && canAffordExpeditedBillLocked(jobStatus));
+                        }
+                    });
+                }
+            });
+        }
+    }
+
     @GuardedBy("mLock")
     public boolean canScheduleEJ(@NonNull JobStatus jobStatus) {
         if (!mIsEnabled) {
@@ -246,6 +274,21 @@
     }
 
     @GuardedBy("mLock")
+    public long getMaxJobExecutionTimeMsLocked(@NonNull JobStatus jobStatus) {
+        if (!mIsEnabled) {
+            return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
+        }
+        if (jobStatus.shouldTreatAsExpeditedJob()) {
+            return mEconomyManagerInternal.getMaxDurationMs(
+                    jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
+                    BILL_JOB_RUNNING_EXPEDITED);
+        }
+        return mEconomyManagerInternal.getMaxDurationMs(
+                jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
+                BILL_JOB_RUNNING_DEFAULT);
+    }
+
+    @GuardedBy("mLock")
     private void addJobToBillList(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
         final int userId = jobStatus.getSourceUserId();
         final String pkgName = jobStatus.getSourcePackageName();
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 74ed334..8a1a07c 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -26,13 +26,15 @@
 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;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -53,6 +55,7 @@
 
 import libcore.util.EmptyArray;
 
+import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.PriorityQueue;
@@ -79,6 +82,8 @@
      * to use older transactions or provide older transactions to apps.
      */
     private static final long MAX_TRANSACTION_AGE_MS = 24 * HOUR_IN_MILLIS;
+    /** The maximum number of transactions to dump per ledger. */
+    private static final int MAX_NUM_TRANSACTION_DUMP = 25;
 
     private static final String ALARM_TAG_AFFORDABILITY_CHECK = "*tare.affordability_check*";
     private static final String ALARM_TAG_LEDGER_CLEANUP = "*tare.ledger_cleanup*";
@@ -127,6 +132,54 @@
     private final BalanceThresholdAlarmListener mBalanceThresholdAlarmListener =
             new BalanceThresholdAlarmListener();
 
+    /**
+     * Comparator to use to sort apps before we distribute ARCs so that we try to give the most
+     * important apps ARCs first.
+     */
+    @VisibleForTesting
+    final Comparator<PackageInfo> mPackageDistributionComparator =
+            new Comparator<PackageInfo>() {
+                @Override
+                public int compare(PackageInfo pi1, PackageInfo pi2) {
+                    final ApplicationInfo appInfo1 = pi1.applicationInfo;
+                    final ApplicationInfo appInfo2 = pi2.applicationInfo;
+                    // Put any packages that don't declare an application at the end. A missing
+                    // <application> tag likely means the app won't be doing any work anyway.
+                    if (appInfo1 == null) {
+                        if (appInfo2 == null) {
+                            return 0;
+                        }
+                        return 1;
+                    } else if (appInfo2 == null) {
+                        return -1;
+                    }
+                    // Privileged apps eat first. They're likely required for the device to
+                    // function properly.
+                    // TODO: include headless system apps
+                    if (appInfo1.isPrivilegedApp()) {
+                        if (!appInfo2.isPrivilegedApp()) {
+                            return -1;
+                        }
+                    } else if (appInfo2.isPrivilegedApp()) {
+                        return 1;
+                    }
+
+                    // Sort by most recently used.
+                    final long timeSinceLastUsedMs1 =
+                            mAppStandbyInternal.getTimeSinceLastUsedByUser(
+                                    pi1.packageName, UserHandle.getUserId(pi1.applicationInfo.uid));
+                    final long timeSinceLastUsedMs2 =
+                            mAppStandbyInternal.getTimeSinceLastUsedByUser(
+                                    pi2.packageName, UserHandle.getUserId(pi2.applicationInfo.uid));
+                    if (timeSinceLastUsedMs1 < timeSinceLastUsedMs2) {
+                        return -1;
+                    } else if (timeSinceLastUsedMs1 > timeSinceLastUsedMs2) {
+                        return 1;
+                    }
+                    return 0;
+                }
+            };
+
     private static final int MSG_CHECK_BALANCE = 0;
     private static final int MSG_CLEAN_LEDGER = 1;
     private static final int MSG_SET_ALARMS = 2;
@@ -183,7 +236,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;
@@ -191,10 +244,21 @@
         return balance;
     }
 
+    /** Returns the total amount of narcs currently allocated to apps. */
+    @GuardedBy("mLock")
+    long getCurrentCirculationLocked() {
+        return mCurrentNarcsInCirculation;
+    }
+
     @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 int eventType = getEventType(eventId);
@@ -231,8 +295,14 @@
     }
 
     @GuardedBy("mLock")
-    void noteOngoingEventLocked(final int userId, @NonNull final String pkgName, final int eventId,
-            @Nullable String tag, final long startElapsed, final boolean updateBalanceCheck) {
+    private void noteOngoingEventLocked(final int userId, @NonNull final String pkgName,
+            final int eventId, @Nullable String tag, final long startElapsed,
+            final boolean updateBalanceCheck) {
+        if (mIrs.isSystem(userId, pkgName)) {
+            // Events are free for the system. Don't bother recording them.
+            return;
+        }
+
         SparseArrayMap<String, OngoingEvent> ongoingEvents =
                 mCurrentOngoingEvents.get(userId, pkgName);
         if (ongoingEvents == null) {
@@ -278,7 +348,7 @@
 
     @GuardedBy("mLock")
     void onDeviceStateChangedLocked() {
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
         final long nowElapsed = SystemClock.elapsedRealtime();
 
         mCurrentOngoingEvents.forEach((userId, pkgName, ongoingEvents) -> {
@@ -326,7 +396,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) {
@@ -391,9 +461,14 @@
      *                                    registered bills and notify listeners about any changes.
      */
     @GuardedBy("mLock")
-    void stopOngoingActionLocked(final int userId, @NonNull final String pkgName, final int eventId,
-            @Nullable String tag, final long nowElapsed, final long now,
+    private void stopOngoingActionLocked(final int userId, @NonNull final String pkgName,
+            final int eventId, @Nullable String tag, final long nowElapsed, final long now,
             final boolean updateBalanceCheck, final boolean notifyOnAffordabilityChange) {
+        if (mIrs.isSystem(userId, pkgName)) {
+            // Events are free for the system. Don't bother recording them.
+            return;
+        }
+
         final Ledger ledger = getLedgerLocked(userId, pkgName);
 
         SparseArrayMap<String, OngoingEvent> ongoingEvents =
@@ -401,7 +476,7 @@
         if (ongoingEvents == null) {
             // 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);
+            Slog.w(TAG, "No ongoing transactions for " + appToString(userId, pkgName));
             return;
         }
         final OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
@@ -410,7 +485,7 @@
             // occurring.
             Slog.w(TAG, "Nonexistent ongoing transaction "
                     + eventToString(eventId) + (tag == null ? "" : ":" + tag)
-                    + " for <" + userId + ">" + pkgName + " ended");
+                    + " for " + appToString(userId, pkgName) + " ended");
             return;
         }
         ongoingEvent.refCount--;
@@ -421,6 +496,7 @@
             recordTransactionLocked(userId, pkgName, ledger,
                     new Ledger.Transaction(startTime, now, eventId, tag, actualDelta),
                     notifyOnAffordabilityChange);
+
             ongoingEvents.delete(eventId, tag);
         }
         if (updateBalanceCheck) {
@@ -442,18 +518,31 @@
                 Math.min(ongoingEvent.reward.maxDailyReward - rewardSum, computedDelta));
     }
 
+    @VisibleForTesting
     @GuardedBy("mLock")
-    private void recordTransactionLocked(final int userId, @NonNull final String pkgName,
+    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) {
-            final long newDelta = maxCirculationAllowed - mCurrentNarcsInCirculation;
+            // Set lower bound at 0 so we don't accidentally take away credits when we were trying
+            // to _give_ the app credits.
+            final long newDelta = Math.max(0, maxCirculationAllowed - mCurrentNarcsInCirculation);
             Slog.i(TAG, "Would result in too many credits in circulation. Decreasing transaction "
                     + eventToString(transaction.eventId)
                     + (transaction.tag == null ? "" : ":" + transaction.tag)
-                    + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta));
+                    + " for " + appToString(userId, pkgName)
+                    + " by " + narcToString(transaction.delta - newDelta));
             transaction = new Ledger.Transaction(
                     transaction.startTimeMs, transaction.endTimeMs,
                     transaction.eventId, transaction.tag, newDelta);
@@ -462,11 +551,15 @@
         if (transaction.delta > 0
                 && originalBalance + transaction.delta
                 > mCompleteEconomicPolicy.getMaxSatiatedBalance()) {
-            final long newDelta = mCompleteEconomicPolicy.getMaxSatiatedBalance() - originalBalance;
+            // Set lower bound at 0 so we don't accidentally take away credits when we were trying
+            // to _give_ the app credits.
+            final long newDelta =
+                    Math.max(0, mCompleteEconomicPolicy.getMaxSatiatedBalance() - originalBalance);
             Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction "
                     + eventToString(transaction.eventId)
                     + (transaction.tag == null ? "" : ":" + transaction.tag)
-                    + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta));
+                    + " for " + appToString(userId, pkgName)
+                    + " by " + narcToString(transaction.delta - newDelta));
             transaction = new Ledger.Transaction(
                     transaction.startTimeMs, transaction.endTimeMs,
                     transaction.eventId, transaction.tag, newDelta);
@@ -477,7 +570,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
@@ -509,7 +602,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;
@@ -529,7 +622,7 @@
                 }
                 if (toReclaim > 0) {
                     Slog.i(TAG, "Reclaiming unused wealth! Taking " + toReclaim
-                            + " from <" + userId + ">" + pkgName);
+                            + " from " + appToString(userId, pkgName));
 
                     recordTransactionLocked(userId, pkgName, ledger,
                             new Ledger.Transaction(
@@ -540,12 +633,29 @@
         }
     }
 
+    /** Returns true if an app should be given credits in the general distributions. */
+    private boolean shouldGiveCredits(@NonNull PackageInfo packageInfo) {
+        final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
+        // Skip apps that wouldn't be doing any work. Giving them ARCs would be wasteful.
+        if (applicationInfo == null || !applicationInfo.hasCode()) {
+            return false;
+        }
+        final int userId = UserHandle.getUserId(packageInfo.applicationInfo.uid);
+        // No point allocating ARCs to the system. It can do whatever it wants.
+        return !mIrs.isSystem(userId, packageInfo.packageName);
+    }
+
     @GuardedBy("mLock")
     void distributeBasicIncomeLocked(int batteryLevel) {
         List<PackageInfo> pkgs = mIrs.getInstalledPackages();
-        final long now = System.currentTimeMillis();
+        pkgs.sort(mPackageDistributionComparator);
+
+        final long now = getCurrentTimeMillis();
         for (int i = 0; i < pkgs.size(); ++i) {
             final PackageInfo pkgInfo = pkgs.get(i);
+            if (!shouldGiveCredits(pkgInfo)) {
+                continue;
+            }
             final int userId = UserHandle.getUserId(pkgInfo.applicationInfo.uid);
             final String pkgName = pkgInfo.packageName;
             Ledger ledger = getLedgerLocked(userId, pkgName);
@@ -574,14 +684,18 @@
 
     @GuardedBy("mLock")
     void grantBirthrightsLocked(final int userId) {
-        PackageManager packageManager = mIrs.getContext().getPackageManager();
-        List<PackageInfo> pkgs = packageManager.getInstalledPackagesAsUser(0, userId);
+        final List<PackageInfo> pkgs = mIrs.getInstalledPackages(userId);
         final long maxBirthright =
                 mIrs.getMaxCirculationLocked() / mIrs.getInstalledPackages().size();
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
+
+        pkgs.sort(mPackageDistributionComparator);
 
         for (int i = 0; i < pkgs.size(); ++i) {
             final PackageInfo packageInfo = pkgs.get(i);
+            if (!shouldGiveCredits(packageInfo)) {
+                continue;
+            }
             final String pkgName = packageInfo.packageName;
             final Ledger ledger = getLedgerLocked(userId, pkgName);
             if (ledger.getCurrentBalance() > 0) {
@@ -609,7 +723,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,
@@ -818,7 +932,7 @@
 
             @Override
             public String toString() {
-                return "<" + userId + ">" + packageName;
+                return appToString(userId, packageName);
             }
 
             @Override
@@ -1257,8 +1371,19 @@
 
     @GuardedBy("mLock")
     void dumpLocked(IndentingPrintWriter pw) {
-        pw.print("Current GDP: ");
-        pw.println(narcToString(mCurrentNarcsInCirculation));
+        pw.println("Ledgers:");
+        pw.increaseIndent();
+        mLedgers.forEach((userId, pkgName, ledger) -> {
+            pw.print(appToString(userId, pkgName));
+            if (mIrs.isSystem(userId, pkgName)) {
+                pw.print(" (system)");
+            }
+            pw.println();
+            pw.increaseIndent();
+            ledger.dump(pw, MAX_NUM_TRANSACTION_DUMP);
+            pw.decreaseIndent();
+        });
+        pw.decreaseIndent();
 
         pw.println();
         mBalanceThresholdAlarmListener.dumpLocked(pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index acdf689..fc057f7 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -16,6 +16,79 @@
 
 package com.android.server.tare;
 
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
+
 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;
@@ -24,6 +97,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
 import android.util.SparseArray;
 
 /**
@@ -31,6 +112,8 @@
  * AlarmManager.
  */
 public class AlarmManagerEconomicPolicy extends EconomicPolicy {
+    private static final String TAG = "TARE- " + AlarmManagerEconomicPolicy.class.getSimpleName();
+
     public static final int ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE =
             TYPE_ACTION | POLICY_AM | 0;
     public static final int ACTION_ALARM_WAKEUP_EXACT =
@@ -57,30 +140,50 @@
             COST_MODIFIER_PROCESS_STATE
     };
 
+    private long mMinSatiatedBalance;
+    private long mMaxSatiatedBalance;
+    private long mMaxSatiatedCirculation;
+
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+    private final SettingsObserver mSettingsObserver;
+    private final InternalResourceService mInternalResourceService;
+
     private final SparseArray<Action> mActions = new SparseArray<>();
     private final SparseArray<Reward> mRewards = new SparseArray<>();
 
     AlarmManagerEconomicPolicy(InternalResourceService irs) {
         super(irs);
-        loadActions();
-        loadRewards();
+        mInternalResourceService = irs;
+        mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
+        loadConstants("");
+    }
+
+    @Override
+    void setup() {
+        super.setup();
+        ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
+        resolver.registerContentObserver(
+                Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS),
+                false, mSettingsObserver, UserHandle.USER_ALL);
+        loadConstants(Settings.Global.getString(
+                mInternalResourceService.getContext().getContentResolver(),
+                TARE_ALARM_MANAGER_CONSTANTS));
     }
 
     @Override
     long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
         // TODO: take exemption into account
-        return arcToNarc(160);
+        return mMinSatiatedBalance;
     }
 
     @Override
     long getMaxSatiatedBalance() {
-        return arcToNarc(1440);
+        return mMaxSatiatedBalance;
     }
 
-
     @Override
     long getMaxSatiatedCirculation() {
-        return arcToNarc(52000);
+        return mMaxSatiatedCirculation;
     }
 
     @NonNull
@@ -101,43 +204,180 @@
         return mRewards.get(rewardId);
     }
 
-    private void loadActions() {
+    private void loadConstants(String policyValuesString) {
+        mActions.clear();
+        mRewards.clear();
+
+        try {
+            mParser.setString(policyValuesString);
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Global setting key incorrect: ", e);
+        }
+
+        mMinSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
+                        DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
+        mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MAX_SATIATED_BALANCE,
+                DEFAULT_AM_MAX_SATIATED_BALANCE));
+        mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_AM_MAX_CIRCULATION,
+                DEFAULT_AM_MAX_CIRCULATION));
+
+        final long exactAllowWhileIdleWakeupBasePrice = arcToNarc(
+                mParser.getInt(KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
+                        DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE));
+
         mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
-                new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(5)));
+                new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP)),
+                        exactAllowWhileIdleWakeupBasePrice));
         mActions.put(ACTION_ALARM_WAKEUP_EXACT,
-                new Action(ACTION_ALARM_WAKEUP_EXACT, arcToNarc(3), arcToNarc(4)));
+                new Action(ACTION_ALARM_WAKEUP_EXACT,
+                        arcToNarc(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP)),
+                        arcToNarc(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
+                                DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE))));
+
+        final long inexactAllowWhileIdleWakeupBasePrice =
+                arcToNarc(mParser.getInt(
+                        KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE,
+                        DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE));
+
         mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
                 new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
-                        arcToNarc(3), arcToNarc(4)));
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP)),
+                        inexactAllowWhileIdleWakeupBasePrice));
         mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
-                new Action(ACTION_ALARM_WAKEUP_INEXACT, arcToNarc(3), arcToNarc(3)));
+                new Action(ACTION_ALARM_WAKEUP_INEXACT,
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
+                                DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE))));
+
+        final long exactAllowWhileIdleNonWakeupBasePrice =
+                arcToNarc(mParser.getInt(
+                        KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
+                        DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+
         mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
                 new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
-                        arcToNarc(1), arcToNarc(3)));
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP)),
+                        exactAllowWhileIdleNonWakeupBasePrice));
         mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
-                new Action(ACTION_ALARM_NONWAKEUP_EXACT, arcToNarc(1), arcToNarc(2)));
+                new Action(ACTION_ALARM_NONWAKEUP_EXACT,
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
+                                DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE))));
+
+        final long inexactAllowWhileIdleNonWakeupBasePrice =
+                arcToNarc(mParser.getInt(
+                        KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
+                        DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+
         mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
                 new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
-                        arcToNarc(1), arcToNarc(2)));
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP)),
+                        inexactAllowWhileIdleNonWakeupBasePrice));
         mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
-                new Action(ACTION_ALARM_NONWAKEUP_INEXACT, arcToNarc(1), arcToNarc(1)));
+                new Action(ACTION_ALARM_NONWAKEUP_INEXACT,
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP,
+                                DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE,
+                                DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE))));
         mActions.put(ACTION_ALARM_CLOCK,
-                new Action(ACTION_ALARM_CLOCK, arcToNarc(5), arcToNarc(10)));
-    }
+                new Action(ACTION_ALARM_CLOCK,
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP,
+                                DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
+                                DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE))));
 
-    private void loadRewards() {
-        mRewards.put(REWARD_TOP_ACTIVITY,
-                new Reward(REWARD_TOP_ACTIVITY,
-                        arcToNarc(0), /* .01 arcs */ arcToNarc(1) / 100, arcToNarc(500)));
-        mRewards.put(REWARD_NOTIFICATION_SEEN,
-                new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(3), arcToNarc(0), arcToNarc(60)));
+        mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
+                        DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT)),
+                (long) (arcToNarc(1) * mParser.getFloat(KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
+                        DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING)),
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_MAX,
+                                DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX))));
+        mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
+                        DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT)),
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
+                        DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING)),
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
+                        DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX))));
         mRewards.put(REWARD_NOTIFICATION_INTERACTION,
                 new Reward(REWARD_NOTIFICATION_INTERACTION,
-                        arcToNarc(5), arcToNarc(0), arcToNarc(500)));
-        mRewards.put(REWARD_WIDGET_INTERACTION,
-                new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT,
+                                DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING,
+                                DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX,
+                                DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX))));
+        mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
+                        DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT)),
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
+                        DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING)),
+                arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
+                        DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX))));
         mRewards.put(REWARD_OTHER_USER_INTERACTION,
                 new Reward(REWARD_OTHER_USER_INTERACTION,
-                        arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+                        arcToNarc(mParser.getInt(KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
+                                DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING,
+                                DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING)),
+                        arcToNarc(mParser.getInt(
+                                KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX,
+                                DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX))));
+    }
+
+    private final class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            loadConstants(Settings.Global.getString(
+                    mInternalResourceService.getContext().getContentResolver(),
+                    TARE_ALARM_MANAGER_CONSTANTS));
+        }
+    }
+
+    @Override
+    void dump(IndentingPrintWriter pw) {
+        pw.println("Actions:");
+        pw.increaseIndent();
+        for (int i = 0; i < mActions.size(); ++i) {
+            dumpAction(pw, mActions.valueAt(i));
+        }
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println("Rewards:");
+        pw.increaseIndent();
+        for (int i = 0; i < mRewards.size(); ++i) {
+            dumpReward(pw, mRewards.valueAt(i));
+        }
+        pw.decreaseIndent();
     }
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index 8c56c61..dbc7bd6 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -67,6 +67,14 @@
     }
 
     @Override
+    void setup() {
+        super.setup();
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            mEnabledEconomicPolicies.valueAt(i).setup();
+        }
+    }
+
+    @Override
     public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
         long min = 0;
         for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
@@ -140,5 +148,35 @@
     @Override
     void dump(IndentingPrintWriter pw) {
         dumpActiveModifiers(pw);
+
+        pw.println();
+        pw.println(getClass().getSimpleName() + ":");
+        pw.increaseIndent();
+
+        pw.println("Cached actions:");
+        pw.increaseIndent();
+        for (int i = 0; i < mActions.size(); ++i) {
+            dumpAction(pw, mActions.valueAt(i));
+        }
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println("Cached rewards:");
+        pw.increaseIndent();
+        for (int i = 0; i < mRewards.size(); ++i) {
+            dumpReward(pw, mRewards.valueAt(i));
+        }
+        pw.decreaseIndent();
+
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); i++) {
+            final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i);
+            pw.println();
+            pw.print("(Includes) ");
+            pw.println(economicPolicy.getClass().getSimpleName() + ":");
+            pw.increaseIndent();
+            economicPolicy.dump(pw);
+            pw.decreaseIndent();
+        }
+        pw.decreaseIndent();
     }
 }
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 fa14d10..d16e378 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -21,6 +21,7 @@
 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.Modifier.NUM_COST_MODIFIERS;
+import static com.android.server.tare.TareUtils.narcToString;
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
@@ -399,4 +400,26 @@
             pw.decreaseIndent();
         }
     }
+
+    protected static void dumpAction(IndentingPrintWriter pw, @NonNull Action action) {
+        pw.print(actionToString(action.id));
+        pw.print(": ");
+        pw.print("ctp=");
+        pw.print(narcToString(action.costToProduce));
+        pw.print(", basePrice=");
+        pw.print(narcToString(action.basePrice));
+        pw.println();
+    }
+
+    protected static void dumpReward(IndentingPrintWriter pw, @NonNull Reward reward) {
+        pw.print(rewardToString(reward.id));
+        pw.print(": ");
+        pw.print("instant=");
+        pw.print(narcToString(reward.instantReward));
+        pw.print(", ongoing/sec=");
+        pw.print(narcToString(reward.ongoingRewardPerSecond));
+        pw.print(", maxDaily=");
+        pw.print(narcToString(reward.maxDailyReward));
+        pw.println();
+    }
 }
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 67d7a95..40ab49c 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -19,10 +19,16 @@
 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.appToString;
+import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
+import static com.android.server.tare.TareUtils.narcToString;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.tare.IEconomyManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,6 +36,7 @@
 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;
@@ -45,6 +52,7 @@
 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;
@@ -52,6 +60,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.UserManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -74,13 +83,17 @@
     static final long UNUSED_RECLAMATION_PERIOD_MS = 24 * HOUR_IN_MILLIS;
     /** How much of an app's unused wealth should be reclaimed periodically. */
     private static final float DEFAULT_UNUSED_RECLAMATION_PERCENTAGE = .1f;
+    private static final int PACKAGE_QUERY_FLAGS =
+            PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                    | PackageManager.MATCH_APEX;
 
-    /** Global local for all resource economy state. */
+    /** Global lock for all resource economy state. */
     private final Object mLock = new Object();
 
     private final Handler mHandler;
     private final BatteryManagerInternal mBatteryManagerInternal;
     private final PackageManager mPackageManager;
+    private final PackageManagerInternal mPackageManagerInternal;
 
     private final Agent mAgent;
     private final CompleteEconomicPolicy mCompleteEconomicPolicy;
@@ -95,6 +108,10 @@
     @GuardedBy("mLock")
     private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
 
+    /** 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.
@@ -104,7 +121,6 @@
     @GuardedBy("mLock")
     private long mLastUnusedReclamationTime;
 
-    @SuppressWarnings("FieldCanBeLocal")
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Nullable
         private String getPackageName(Intent intent) {
@@ -153,13 +169,25 @@
         }
     };
 
+    private final UsageStatsManagerInternal.UsageEventListener mSurveillanceAgent =
+            new UsageStatsManagerInternal.UsageEventListener() {
+                /**
+                 * Callback to inform listeners of a new event.
+                 */
+                @Override
+                public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
+                    mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event)
+                            .sendToTarget();
+                }
+            };
+
     private final AlarmManager.OnAlarmListener mUnusedWealthReclamationListener =
             new AlarmManager.OnAlarmListener() {
                 @Override
                 public void onAlarm() {
                     synchronized (mLock) {
                         mAgent.reclaimUnusedAssetsLocked(DEFAULT_UNUSED_RECLAMATION_PERCENTAGE);
-                        mLastUnusedReclamationTime = System.currentTimeMillis();
+                        mLastUnusedReclamationTime = getCurrentTimeMillis();
                         scheduleUnusedWealthReclamationLocked();
                     }
                 }
@@ -167,6 +195,7 @@
 
     private static final int MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER = 0;
     private static final int MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT = 1;
+    private static final int MSG_PROCESS_USAGE_EVENT = 2;
     private static final String ALARM_TAG_WEALTH_RECLAMATION = "*tare.reclamation*";
     private static final String KEY_PKG = "pkg";
 
@@ -185,6 +214,7 @@
         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);
@@ -214,6 +244,7 @@
         return mLock;
     }
 
+    /** Returns the installed packages for all users. */
     @NonNull
     List<PackageInfo> getInstalledPackages() {
         synchronized (mLock) {
@@ -221,6 +252,22 @@
         }
     }
 
+    /** Returns the installed packages for the specified user. */
+    @NonNull
+    List<PackageInfo> getInstalledPackages(final int userId) {
+        final List<PackageInfo> userPkgs = new ArrayList<>();
+        synchronized (mLock) {
+            for (int i = 0; i < mPkgCache.size(); ++i) {
+                final PackageInfo packageInfo = mPkgCache.get(i);
+                if (packageInfo.applicationInfo != null
+                        && UserHandle.getUserId(packageInfo.applicationInfo.uid) == userId) {
+                    userPkgs.add(packageInfo);
+                }
+            }
+        }
+        return userPkgs;
+    }
+
     @GuardedBy("mLock")
     long getMaxCirculationLocked() {
         return mCurrentBatteryLevel * mCompleteEconomicPolicy.getMaxSatiatedCirculation() / 100;
@@ -232,10 +279,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();
@@ -256,11 +321,15 @@
         final int userId = UserHandle.getUserId(uid);
         final PackageInfo packageInfo;
         try {
-            packageInfo = mPackageManager.getPackageInfoAsUser(pkgName, 0, userId);
+            packageInfo =
+                    mPackageManager.getPackageInfoAsUser(pkgName, PACKAGE_QUERY_FLAGS, userId);
         } catch (PackageManager.NameNotFoundException e) {
-            Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName);
+            Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName, e);
             return;
         }
+        synchronized (mPackageToUidCache) {
+            mPackageToUidCache.add(userId, pkgName, uid);
+        }
         synchronized (mLock) {
             mPkgCache.add(packageInfo);
             mUidToPackageCache.add(uid, pkgName);
@@ -277,6 +346,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) {
@@ -304,7 +376,8 @@
 
     void onUserAdded(final int userId) {
         synchronized (mLock) {
-            loadInstalledPackageListLocked();
+            mPkgCache.addAll(
+                    mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId));
             mAgent.grantBirthrightsLocked(userId);
         }
     }
@@ -321,7 +394,6 @@
                     break;
                 }
             }
-            loadInstalledPackageListLocked();
             mAgent.onUserRemovedLocked(userId, removedPkgs);
         }
     }
@@ -341,8 +413,44 @@
     }
 
     @GuardedBy("mLock")
+    private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) {
+        if (!mIsEnabled) {
+            return;
+        }
+        final String pkgName = event.getPackageName();
+        if (DEBUG) {
+            Slog.d(TAG, "Processing event " + event.getEventType()
+                    + " for " + appToString(userId, pkgName));
+        }
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        switch (event.getEventType()) {
+            case UsageEvents.Event.ACTIVITY_RESUMED:
+                mAgent.noteOngoingEventLocked(userId, pkgName,
+                        EconomicPolicy.REWARD_TOP_ACTIVITY, null, nowElapsed);
+                break;
+            case UsageEvents.Event.ACTIVITY_PAUSED:
+            case UsageEvents.Event.ACTIVITY_STOPPED:
+            case UsageEvents.Event.ACTIVITY_DESTROYED:
+                final long now = getCurrentTimeMillis();
+                mAgent.stopOngoingActionLocked(userId, pkgName,
+                        EconomicPolicy.REWARD_TOP_ACTIVITY, null, nowElapsed, now);
+                break;
+            case UsageEvents.Event.USER_INTERACTION:
+            case UsageEvents.Event.CHOOSER_ACTION:
+                mAgent.noteInstantaneousEventLocked(userId, pkgName,
+                        EconomicPolicy.REWARD_OTHER_USER_INTERACTION, null);
+                break;
+            case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+            case UsageEvents.Event.NOTIFICATION_SEEN:
+                mAgent.noteInstantaneousEventLocked(userId, pkgName,
+                        EconomicPolicy.REWARD_NOTIFICATION_SEEN, null);
+                break;
+        }
+    }
+
+    @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(() -> {
@@ -382,10 +490,17 @@
 
     @GuardedBy("mLock")
     private void loadInstalledPackageListLocked() {
-        mPkgCache = mPackageManager.getInstalledPackages(0);
+        mPkgCache.clear();
+        final UserManagerInternal userManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+        final int[] userIds = userManagerInternal.getUserIds();
+        for (int userId : userIds) {
+            mPkgCache.addAll(
+                    mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId));
+        }
     }
 
-    private void registerReceivers() {
+    private void registerListeners() {
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
@@ -402,6 +517,9 @@
         userFilter.addAction(Intent.ACTION_USER_ADDED);
         getContext()
                 .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+
+        UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
+        usmi.registerListener(mSurveillanceAgent);
     }
 
     /** Perform long-running and/or heavy setup work. This should be called off the main thread. */
@@ -421,7 +539,7 @@
             return;
         }
         synchronized (mLock) {
-            registerReceivers();
+            registerListeners();
             mCurrentBatteryLevel = getCurrentBatteryLevel();
             mHandler.post(this::setupHeavyWork);
             scheduleUnusedWealthReclamationLocked();
@@ -446,6 +564,12 @@
             mPkgCache.clear();
             mUidToPackageCache.clear();
             getContext().unregisterReceiver(mBroadcastReceiver);
+            UsageStatsManagerInternal usmi =
+                    LocalServices.getService(UsageStatsManagerInternal.class);
+            usmi.unregisterListener(mSurveillanceAgent);
+        }
+        synchronized (mPackageToUidCache) {
+            mPackageToUidCache.clear();
         }
     }
 
@@ -471,6 +595,15 @@
                 }
                 break;
 
+                case MSG_PROCESS_USAGE_EVENT: {
+                    final int userId = msg.arg1;
+                    final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
+                    synchronized (mLock) {
+                        processUsageEventLocked(userId, event);
+                    }
+                }
+                break;
+
                 case MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT: {
                     removeMessages(MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT);
                     synchronized (mLock) {
@@ -498,6 +631,10 @@
                 if ("-h".equals(arg) || "--help".equals(arg)) {
                     dumpHelp(pw);
                     return;
+                } else if ("-a".equals(arg)) {
+                    // -a is passed when dumping a bug report so we have to acknowledge the
+                    // argument. However, we currently don't do anything differently for bug
+                    // reports.
                 } else if (arg.length() > 0 && arg.charAt(0) == '-') {
                     pw.println("Unknown option: " + arg);
                     return;
@@ -514,9 +651,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);
             }
@@ -525,6 +675,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);
             }
@@ -535,6 +689,11 @@
             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 =
@@ -552,6 +711,32 @@
         }
 
         @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) {
@@ -581,7 +766,7 @@
                 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);
             }
@@ -630,12 +815,29 @@
 
     private void dumpInternal(final IndentingPrintWriter pw) {
         synchronized (mLock) {
+            pw.print("Is enabled: ");
+            pw.println(mIsEnabled);
+
             pw.print("Current battery level: ");
             pw.println(mCurrentBatteryLevel);
 
-            mCompleteEconomicPolicy.dump(pw);
-            pw.println();
+            final long maxCircluation = getMaxCirculationLocked();
+            pw.print("Max circulation (current/satiated): ");
+            pw.print(narcToString(maxCircluation));
+            pw.print("/");
+            pw.println(narcToString(mCompleteEconomicPolicy.getMaxSatiatedCirculation()));
 
+            final long currentCirculation = mAgent.getCurrentCirculationLocked();
+            pw.print("Current GDP: ");
+            pw.print(narcToString(currentCirculation));
+            pw.print(" (");
+            pw.print(String.format("%.2f", 100f * currentCirculation / maxCircluation));
+            pw.println("% of current max)");
+
+            pw.println();
+            mCompleteEconomicPolicy.dump(pw);
+
+            pw.println();
             mAgent.dumpLocked(pw);
         }
     }
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 ff008a2..c332f2f 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -16,6 +16,88 @@
 
 package com.android.server.tare;
 
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
+
 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;
@@ -24,6 +106,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
 import android.util.SparseArray;
 
 /**
@@ -31,6 +121,8 @@
  * JobScheduler.
  */
 public class JobSchedulerEconomicPolicy extends EconomicPolicy {
+    private static final String TAG = "TARE- " + JobSchedulerEconomicPolicy.class.getSimpleName();
+
     public static final int ACTION_JOB_MAX_START = TYPE_ACTION | POLICY_JS | 0;
     public static final int ACTION_JOB_MAX_RUNNING = TYPE_ACTION | POLICY_JS | 1;
     public static final int ACTION_JOB_HIGH_START = TYPE_ACTION | POLICY_JS | 2;
@@ -50,29 +142,50 @@
             COST_MODIFIER_PROCESS_STATE
     };
 
+    private long mMinSatiatedBalance;
+    private long mMaxSatiatedBalance;
+    private long mMaxSatiatedCirculation;
+
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+    private final SettingsObserver mSettingsObserver;
+    private final InternalResourceService mInternalResourceService;
+
     private final SparseArray<Action> mActions = new SparseArray<>();
     private final SparseArray<Reward> mRewards = new SparseArray<>();
 
     JobSchedulerEconomicPolicy(InternalResourceService irs) {
         super(irs);
-        loadActions();
-        loadRewards();
+        mInternalResourceService = irs;
+        mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
+        loadConstants("");
+    }
+
+    @Override
+    void setup() {
+        super.setup();
+        ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
+        resolver.registerContentObserver(
+                Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS),
+                false, mSettingsObserver, UserHandle.USER_ALL);
+        loadConstants(Settings.Global.getString(
+                mInternalResourceService.getContext().getContentResolver(),
+                TARE_JOB_SCHEDULER_CONSTANTS));
     }
 
     @Override
     long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
         // TODO: incorporate time since usage
-        return arcToNarc(2000);
+        return mMinSatiatedBalance;
     }
 
     @Override
     long getMaxSatiatedBalance() {
-        return arcToNarc(60000);
+        return mMaxSatiatedBalance;
     }
 
     @Override
     long getMaxSatiatedCirculation() {
-        return arcToNarc(691200);
+        return mMaxSatiatedCirculation;
     }
 
     @NonNull
@@ -93,45 +206,152 @@
         return mRewards.get(rewardId);
     }
 
-    private void loadActions() {
-        mActions.put(ACTION_JOB_MAX_START,
-                new Action(ACTION_JOB_MAX_START, arcToNarc(3), arcToNarc(10)));
-        mActions.put(ACTION_JOB_MAX_RUNNING,
-                new Action(ACTION_JOB_MAX_RUNNING, arcToNarc(2), arcToNarc(5)));
-        mActions.put(ACTION_JOB_HIGH_START,
-                new Action(ACTION_JOB_HIGH_START, arcToNarc(3), arcToNarc(8)));
-        mActions.put(ACTION_JOB_HIGH_RUNNING,
-                new Action(ACTION_JOB_HIGH_RUNNING, arcToNarc(2), arcToNarc(4)));
-        mActions.put(ACTION_JOB_DEFAULT_START,
-                new Action(ACTION_JOB_DEFAULT_START, arcToNarc(3), arcToNarc(6)));
-        mActions.put(ACTION_JOB_DEFAULT_RUNNING,
-                new Action(ACTION_JOB_DEFAULT_RUNNING, arcToNarc(2), arcToNarc(3)));
-        mActions.put(ACTION_JOB_LOW_START,
-                new Action(ACTION_JOB_LOW_START, arcToNarc(3), arcToNarc(4)));
-        mActions.put(ACTION_JOB_LOW_RUNNING,
-                new Action(ACTION_JOB_LOW_RUNNING, arcToNarc(2), arcToNarc(2)));
-        mActions.put(ACTION_JOB_MIN_START,
-                new Action(ACTION_JOB_MIN_START, arcToNarc(3), arcToNarc(2)));
-        mActions.put(ACTION_JOB_MIN_RUNNING,
-                new Action(ACTION_JOB_MIN_RUNNING, arcToNarc(2), arcToNarc(1)));
-        mActions.put(ACTION_JOB_TIMEOUT,
-                new Action(ACTION_JOB_TIMEOUT, arcToNarc(30), arcToNarc(60)));
-    }
+    private void loadConstants(String policyValuesString) {
+        mActions.clear();
+        mRewards.clear();
 
-    private void loadRewards() {
-        mRewards.put(REWARD_TOP_ACTIVITY,
-                new Reward(REWARD_TOP_ACTIVITY,
-                        arcToNarc(0), /* .5 arcs */ arcToNarc(5) / 10, arcToNarc(15000)));
-        mRewards.put(REWARD_NOTIFICATION_SEEN,
-                new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(1), arcToNarc(0), arcToNarc(10)));
+        try {
+            mParser.setString(policyValuesString);
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Global setting key incorrect: ", e);
+        }
+
+        mMinSatiatedBalance = arcToNarc(
+                mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
+                        DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP));
+        mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_JS_MAX_SATIATED_BALANCE,
+                DEFAULT_JS_MAX_SATIATED_BALANCE));
+        mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_JS_MAX_CIRCULATION,
+                DEFAULT_JS_MAX_CIRCULATION));
+
+        mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_CTP,
+                        DEFAULT_JS_ACTION_JOB_MAX_START_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE))));
+        mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_CTP,
+                        DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE))));
+        mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_CTP,
+                        DEFAULT_JS_ACTION_JOB_HIGH_START_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE))));
+        mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP,
+                        DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE))));
+        mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_CTP,
+                        DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE))));
+        mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP,
+                        DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE))));
+        mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_CTP,
+                        DEFAULT_JS_ACTION_JOB_LOW_START_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE))));
+        mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_CTP,
+                        DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE))));
+        mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_CTP,
+                        DEFAULT_JS_ACTION_JOB_MIN_START_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE))));
+        mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_CTP,
+                        DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE))));
+        mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT,
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP,
+                        DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP)),
+                arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE,
+                        DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE))));
+
+        mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
+                        DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT)),
+                (long) (arcToNarc(1) * mParser.getFloat(KEY_JS_REWARD_TOP_ACTIVITY_ONGOING,
+                        DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING)),
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_MAX,
+                        DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX))));
+        mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT,
+                        DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT)),
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING,
+                        DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING)),
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_MAX,
+                        DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX))));
         mRewards.put(REWARD_NOTIFICATION_INTERACTION,
                 new Reward(REWARD_NOTIFICATION_INTERACTION,
-                        arcToNarc(5), arcToNarc(0), arcToNarc(5000)));
-        mRewards.put(REWARD_WIDGET_INTERACTION,
-                new Reward(REWARD_WIDGET_INTERACTION,
-                        arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+                        arcToNarc(mParser.getInt(
+                                KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT,
+                                DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
+                        arcToNarc(mParser.getInt(
+                                KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING,
+                                DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
+                        arcToNarc(mParser.getInt(
+                                KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX,
+                                DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX))));
+        mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT,
+                        DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT)),
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING,
+                        DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING)),
+                arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_MAX,
+                        DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX))));
         mRewards.put(REWARD_OTHER_USER_INTERACTION,
                 new Reward(REWARD_OTHER_USER_INTERACTION,
-                        arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+                        arcToNarc(mParser.getInt(KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT,
+                                DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT)),
+                        arcToNarc(mParser.getInt(
+                                KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING,
+                                DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING)),
+                        arcToNarc(mParser.getInt(
+                                KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
+                                DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX))));
+    }
+
+    private final class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            loadConstants(Settings.Global.getString(
+                    mInternalResourceService.getContext().getContentResolver(),
+                    TARE_JOB_SCHEDULER_CONSTANTS));
+        }
+    }
+
+    @Override
+    void dump(IndentingPrintWriter pw) {
+        pw.println("Actions:");
+        pw.increaseIndent();
+        for (int i = 0; i < mActions.size(); ++i) {
+            dumpAction(pw, mActions.valueAt(i));
+        }
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println("Rewards:");
+        pw.increaseIndent();
+        for (int i = 0; i < mRewards.size(); ++i) {
+            dumpReward(pw, mRewards.valueAt(i));
+        }
+        pw.decreaseIndent();
     }
 }
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..f2b78c0 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,15 +110,19 @@
 
     /** 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);
         }
     }
 
-    void dump(IndentingPrintWriter pw) {
+    void dump(IndentingPrintWriter pw, int numRecentTransactions) {
         pw.print("Current balance", narcToString(getCurrentBalance())).println();
-        mTransactions.forEach((transaction) -> {
+
+        final int size = mTransactions.size();
+        for (int i = Math.max(0, size - numRecentTransactions); i < size; ++i) {
+            final Transaction transaction = mTransactions.get(i);
+
             dumpTime(pw, transaction.startTimeMs);
             pw.print("--");
             dumpTime(pw, transaction.endTimeMs);
@@ -125,6 +130,6 @@
             pw.print(EconomicPolicy.eventToString(transaction.eventId));
             pw.print(" --> ");
             pw.println(narcToString(transaction.delta));
-        });
+        }
     }
 }
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 92a2014a..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,7 +102,6 @@
     ProcessStateModifier(@NonNull InternalResourceService irs) {
         super();
         mIrs = irs;
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
     }
 
     @Override
@@ -143,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:
@@ -166,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..78508d4 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);
     }
@@ -49,14 +59,25 @@
         final long sub = Math.abs(narcs) % NARC_IN_ARC;
         final long arcs = narcToArc(narcs);
         if (arcs == 0) {
-            return sub + " narcs";
+            return sub == 1
+                    ? sub + " narc"
+                    : sub + " narcs";
         }
         StringBuilder sb = new StringBuilder();
         sb.append(arcs);
         if (sub > 0) {
             sb.append(".").append(sub / (NARC_IN_ARC / 1000));
         }
-        sb.append(" ARCs");
+        sb.append(" ARC");
+        if (arcs != 1 || sub > 0) {
+            sb.append("s");
+        }
         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/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 2fa10f0..096211b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -264,6 +264,11 @@
     // get the cached value
     private static final long NETWORK_SCORER_CACHE_DURATION_MILLIS = 5000L;
 
+    // Cache the device provisioning package queried from resource config_deviceProvisioningPackage.
+    // Note that there is no synchronization on this method which is okay since in the worst case
+    // scenario, they might be a few extra reads from resources.
+    private String mCachedDeviceProvisioningPackage = null;
+
     // Messages for the handler
     static final int MSG_INFORM_LISTENERS = 3;
     static final int MSG_FORCE_IDLE_STATE = 4;
@@ -1641,9 +1646,11 @@
      * returns {@code false}.
      */
     private boolean isDeviceProvisioningPackage(String packageName) {
-        String deviceProvisioningPackage = mContext.getResources().getString(
-                com.android.internal.R.string.config_deviceProvisioningPackage);
-        return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
+        if (mCachedDeviceProvisioningPackage == null) {
+            mCachedDeviceProvisioningPackage = mContext.getResources().getString(
+                    com.android.internal.R.string.config_deviceProvisioningPackage);
+        }
+        return mCachedDeviceProvisioningPackage.equals(packageName);
     }
 
     private boolean isCarrierApp(String packageName) {
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
index ced2fb5..73f02d3 100644
--- a/apex/media/OWNERS
+++ b/apex/media/OWNERS
@@ -1,10 +1,10 @@
-andrewlewis@google.com
-aquilescanta@google.com
-chz@google.com
+# Bug component: 1344
 hdmoon@google.com
 hkuang@google.com
 jinpark@google.com
 klhyun@google.com
 lnilsson@google.com
-marcone@google.com
 sungsoo@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
index fb3172b..e1c89e9 100644
--- a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
+++ b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
@@ -18,6 +18,7 @@
 import android.media.Session2Token;
 import android.media.IMediaCommunicationServiceCallback;
 import android.media.MediaParceledListSlice;
+import android.view.KeyEvent;
 
 /** {@hide} */
 interface IMediaCommunicationService {
@@ -25,6 +26,8 @@
     boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
     MediaParceledListSlice getSession2Tokens(int userId);
 
+   void dispatchMediaKeyEvent(String packageName, in KeyEvent keyEvent, boolean asSystemService);
+
     void registerCallback(IMediaCommunicationServiceCallback callback, String packageName);
     void unregisterCallback(IMediaCommunicationServiceCallback callback);
 }
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 1bf732b..d963e68 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -120,7 +120,7 @@
     srcs: [
         "java/android/media/ApplicationMediaCapabilities.java",
         "java/android/media/MediaFeature.java",
-        "java/android/media/MediaTranscodeManager.java",
+        "java/android/media/MediaTranscodingManager.java",
     ],
     path: "java",
 }
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index eb6397a1..7317f14 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -2,6 +2,7 @@
 package android.media {
 
   public class MediaCommunicationManager {
+    method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean);
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaCommunicationManager.SessionCallback);
     method public void unregisterSessionCallback(@NonNull android.media.MediaCommunicationManager.SessionCallback);
   }
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index ce68447..6eea769 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -1,15 +1,15 @@
 // Signature format: 2.0
 package android.media {
 
-  public final class MediaTranscodeManager {
-    method @Nullable public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener);
+  public final class MediaTranscodingManager {
+    method @Nullable public android.media.MediaTranscodingManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodingManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodingManager.OnTranscodingFinishedListener);
   }
 
-  @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
-    method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
+  @java.lang.FunctionalInterface public static interface MediaTranscodingManager.OnTranscodingFinishedListener {
+    method public void onTranscodingFinished(@NonNull android.media.MediaTranscodingManager.TranscodingSession);
   }
 
-  public abstract static class MediaTranscodeManager.TranscodingRequest {
+  public abstract static class MediaTranscodingManager.TranscodingRequest {
     method public int getClientPid();
     method public int getClientUid();
     method @Nullable public android.os.ParcelFileDescriptor getDestinationFileDescriptor();
@@ -18,13 +18,13 @@
     method @NonNull public android.net.Uri getSourceUri();
   }
 
-  public static class MediaTranscodeManager.TranscodingRequest.VideoFormatResolver {
-    ctor public MediaTranscodeManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat);
+  public static class MediaTranscodingManager.TranscodingRequest.VideoFormatResolver {
+    ctor public MediaTranscodingManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat);
     method @Nullable public android.media.MediaFormat resolveVideoFormat();
     method public boolean shouldTranscode();
   }
 
-  public static final class MediaTranscodeManager.TranscodingSession {
+  public static final class MediaTranscodingManager.TranscodingSession {
     method public boolean addClientUid(int);
     method public void cancel();
     method @NonNull public java.util.List<java.lang.Integer> getClientUids();
@@ -33,7 +33,7 @@
     method public int getResult();
     method public int getSessionId();
     method public int getStatus();
-    method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
+    method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener);
     field public static final int ERROR_DROPPED_BY_SERVICE = 1; // 0x1
     field public static final int ERROR_NONE = 0; // 0x0
     field public static final int ERROR_SERVICE_DIED = 2; // 0x2
@@ -47,21 +47,21 @@
     field public static final int STATUS_RUNNING = 2; // 0x2
   }
 
-  @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
-    method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
+  @java.lang.FunctionalInterface public static interface MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener {
+    method public void onProgressUpdate(@NonNull android.media.MediaTranscodingManager.TranscodingSession, @IntRange(from=0, to=100) int);
   }
 
-  public static final class MediaTranscodeManager.VideoTranscodingRequest extends android.media.MediaTranscodeManager.TranscodingRequest {
+  public static final class MediaTranscodingManager.VideoTranscodingRequest extends android.media.MediaTranscodingManager.TranscodingRequest {
     method @NonNull public android.media.MediaFormat getVideoTrackFormat();
   }
 
-  public static final class MediaTranscodeManager.VideoTranscodingRequest.Builder {
-    ctor public MediaTranscodeManager.VideoTranscodingRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.media.MediaFormat);
-    method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest build();
-    method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setClientPid(int);
-    method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setClientUid(int);
-    method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setDestinationFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
-    method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setSourceFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
+  public static final class MediaTranscodingManager.VideoTranscodingRequest.Builder {
+    ctor public MediaTranscodingManager.VideoTranscodingRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.media.MediaFormat);
+    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest build();
+    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientPid(int);
+    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientUid(int);
+    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setDestinationFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setSourceFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
   }
 
 }
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index f39bcfb..b2528cd 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -32,6 +32,7 @@
 import android.os.UserHandle;
 import android.service.media.MediaBrowserService;
 import android.util.Log;
+import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.modules.annotation.MinSdk;
@@ -63,7 +64,8 @@
     private static final int CURRENT_VERSION = VERSION_1;
 
     private final Context mContext;
-    private final IMediaCommunicationService mService;
+    // Do not access directly use getService().
+    private IMediaCommunicationService mService;
 
     private final Object mLock = new Object();
     private final CopyOnWriteArrayList<SessionCallbackRecord> mTokenCallbackRecords =
@@ -80,10 +82,6 @@
             throw new UnsupportedOperationException("Android version must be S or greater.");
         }
         mContext = context;
-        mService = IMediaCommunicationService.Stub.asInterface(
-                MediaFrameworkInitializer.getMediaServiceManager()
-                        .getMediaCommunicationServiceRegisterer()
-                        .get());
     }
 
     /**
@@ -105,7 +103,7 @@
             throw new IllegalArgumentException("token's type should be TYPE_SESSION");
         }
         try {
-            mService.notifySession2Created(token);
+            getService().notifySession2Created(token);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -130,7 +128,7 @@
             return false;
         }
         try {
-            return mService.isTrusted(
+            return getService().isTrusted(
                     userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid());
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot communicate with the service.", e);
@@ -182,7 +180,7 @@
                 MediaCommunicationServiceCallbackStub callbackStub =
                         new MediaCommunicationServiceCallbackStub();
                 try {
-                    mService.registerCallback(callbackStub, mContext.getPackageName());
+                    getService().registerCallback(callbackStub, mContext.getPackageName());
                     mCallbackStub = callbackStub;
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Failed to register callback.", ex);
@@ -205,7 +203,7 @@
         synchronized (mLock) {
             if (mCallbackStub != null && mTokenCallbackRecords.isEmpty()) {
                 try {
-                    mService.unregisterCallback(mCallbackStub);
+                    getService().unregisterCallback(mCallbackStub);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Failed to unregister callback.", ex);
                 }
@@ -214,9 +212,19 @@
         }
     }
 
+    private IMediaCommunicationService getService() {
+        if (mService == null) {
+            mService = IMediaCommunicationService.Stub.asInterface(
+                    MediaFrameworkInitializer.getMediaServiceManager()
+                            .getMediaCommunicationServiceRegisterer()
+                            .get());
+        }
+        return mService;
+    }
+
     private List<Session2Token> getSession2Tokens(int userId) {
         try {
-            MediaParceledListSlice slice = mService.getSession2Tokens(userId);
+            MediaParceledListSlice slice = getService().getSession2Tokens(userId);
             return slice == null ? Collections.emptyList() : slice.getList();
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to get session tokens", e);
@@ -225,6 +233,25 @@
     }
 
     /**
+     * Sends a media key event. The receiver will be selected automatically.
+     *
+     * @param keyEvent the key event to send
+     * @param asSystemService if {@code true}, the event sent to the session as if it was come from
+     *                        the system service instead of the app process.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean asSystemService) {
+        Objects.requireNonNull(keyEvent, "keyEvent shouldn't be null");
+        try {
+            getService().dispatchMediaKeyEvent(mContext.getPackageName(),
+                    keyEvent, asSystemService);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to send key event.", e);
+        }
+    }
+
+    /**
      * Callback for listening to changes to the sessions.
      * @see #registerSessionCallback(Executor, SessionCallback)
      * @hide
diff --git a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
index de2924e..75a56b72 100644
--- a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
+++ b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
@@ -75,8 +75,8 @@
     public static void registerServiceWrappers() {
         SystemServiceRegistry.registerContextAwareService(
                 Context.MEDIA_TRANSCODING_SERVICE,
-                MediaTranscodeManager.class,
-                context -> new MediaTranscodeManager(context)
+                MediaTranscodingManager.class,
+                context -> new MediaTranscodingManager(context)
         );
         if (SdkLevel.isAtLeastS()) {
             SystemServiceRegistry.registerContextAwareService(
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java
similarity index 98%
rename from apex/media/framework/java/android/media/MediaTranscodeManager.java
rename to apex/media/framework/java/android/media/MediaTranscodingManager.java
index 5742d43..7e4799c 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodingManager.java
@@ -22,7 +22,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -54,7 +53,7 @@
 /**
  Android 12 introduces Compatible media transcoding feature.  See
  <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
- Compatible media transcoding</a>. MediaTranscodeManager provides an interface to the system's media
+ Compatible media transcoding</a>. MediaTranscodingManager provides an interface to the system's media
  transcoding service and can be used to transcode media files, e.g. transcoding a video from HEVC to
  AVC.
 
@@ -69,7 +68,7 @@
  <p>
  To transcode a media file, first create a {@link TranscodingRequest} through its builder class
  {@link VideoTranscodingRequest.Builder}. Transcode requests are then enqueue to the manager through
- {@link MediaTranscodeManager#enqueueRequest(
+ {@link MediaTranscodingManager#enqueueRequest(
          TranscodingRequest, Executor, OnTranscodingFinishedListener)}
  TranscodeRequest are processed based on client process's priority and request priority. When a
  transcode operation is completed the caller is notified via its
@@ -87,8 +86,8 @@
  */
 @MinSdk(Build.VERSION_CODES.S)
 @SystemApi
-public final class MediaTranscodeManager {
-    private static final String TAG = "MediaTranscodeManager";
+public final class MediaTranscodingManager {
+    private static final String TAG = "MediaTranscodingManager";
 
     /** Maximum number of retry to connect to the service. */
     private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
@@ -121,13 +120,12 @@
     private final String mPackageName;
     private final int mPid;
     private final int mUid;
-    private final boolean mIsLowRamDevice;
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
     private final HashMap<Integer, TranscodingSession> mPendingTranscodingSessions = new HashMap();
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     @NonNull private ITranscodingClient mTranscodingClient = null;
-    private static MediaTranscodeManager sMediaTranscodeManager;
+    private static MediaTranscodingManager sMediaTranscodingManager;
 
     private void handleTranscodingFinished(int sessionId, TranscodingResultParcel result) {
         synchronized (mPendingTranscodingSessions) {
@@ -208,10 +206,7 @@
         if (!SdkLevel.isAtLeastS()) {
             return null;
         }
-        // Do not try to get the service on AndroidGo (low-ram) devices.
-        if (mIsLowRamDevice) {
-            return null;
-        }
+
         int retryCount = !retry ? 1 :  CONNECT_SERVICE_RETRY_COUNT;
         Log.i(TAG, "get service with retry " + retryCount);
         for (int count = 1;  count <= retryCount; count++) {
@@ -306,7 +301,7 @@
                 }
 
                 try {
-                    // Do not set hasRetried for retry initiated by MediaTranscodeManager.
+                    // Do not set hasRetried for retry initiated by MediaTranscodingManager.
                     session.retryInternal(false /*setHasRetried*/);
                 } catch (Exception re) {
                     // TODO(hkuang): Return correct error code to the client.
@@ -423,13 +418,12 @@
     /**
      * @hide
      */
-    public MediaTranscodeManager(@NonNull Context context) {
+    public MediaTranscodingManager(@NonNull Context context) {
         mContext = context;
         mContentResolver = mContext.getContentResolver();
         mPackageName = mContext.getPackageName();
         mUid = Os.getuid();
         mPid = Os.getpid();
-        mIsLowRamDevice = mContext.getSystemService(ActivityManager.class).isLowRamDevice();
     }
 
     /**
@@ -1348,7 +1342,7 @@
                     @IntRange(from = 0, to = 100) int progress);
         }
 
-        private final MediaTranscodeManager mManager;
+        private final MediaTranscodingManager mManager;
         private Executor mListenerExecutor;
         private OnTranscodingFinishedListener mListener;
         private int mSessionId = -1;
@@ -1374,7 +1368,7 @@
         private final TranscodingRequest mRequest;
 
         private TranscodingSession(
-                @NonNull MediaTranscodeManager manager,
+                @NonNull MediaTranscodingManager manager,
                 @NonNull TranscodingRequest request,
                 @NonNull TranscodingSessionParcel parcel,
                 @NonNull @CallbackExecutor Executor executor,
@@ -1675,10 +1669,10 @@
 
     /**
      * Enqueues a TranscodingRequest for execution.
-     * <p> Upon successfully accepting the request, MediaTranscodeManager will return a
+     * <p> Upon successfully accepting the request, MediaTranscodingManager will return a
      * {@link TranscodingSession} to the client. Client should use {@link TranscodingSession} to
      * track the progress and get the result.
-     * <p> MediaTranscodeManager will return null if fails to accept the request due to service
+     * <p> MediaTranscodingManager will return null if fails to accept the request due to service
      * rebooting. Client could retry again after receiving null.
      *
      * @param transcodingRequest The TranscodingRequest to enqueue.
diff --git a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
index ed31aa3..03a2372 100644
--- a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
+++ b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
@@ -31,6 +31,7 @@
 import android.media.MediaParceledListSlice;
 import android.media.Session2CommandGroup;
 import android.media.Session2Token;
+import android.media.session.MediaSessionManager;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -42,6 +43,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
@@ -60,7 +62,7 @@
  * @hide
  */
 public class MediaCommunicationService extends SystemService {
-    private static final String TAG = "MediaCommunicationService";
+    private static final String TAG = "MediaCommunicationSrv";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     final Context mContext;
@@ -77,6 +79,7 @@
     @GuardedBy("mLock")
     final List<CallbackRecord> mCallbackRecords = new ArrayList<>();
     final NotificationManager mNotificationManager;
+    MediaSessionManager mSessionManager;
 
     public MediaCommunicationService(Context context) {
         super(context);
@@ -91,6 +94,17 @@
     }
 
     @Override
+    public void onBootPhase(int phase) {
+        super.onBootPhase(phase);
+        switch (phase) {
+            // This ensures MediaSessionService is started
+            case PHASE_BOOT_COMPLETED:
+                mSessionManager = mContext.getSystemService(MediaSessionManager.class);
+                break;
+        }
+    }
+
+    @Override
     public void onUserStarting(@NonNull TargetUser user) {
         if (DEBUG) Log.d(TAG, "onUserStarting: " + user);
         updateUser();
@@ -267,6 +281,24 @@
         session.close();
     }
 
+    static boolean isMediaSessionKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                return true;
+        }
+        return false;
+    }
+
     private class Stub extends IMediaCommunicationService.Stub {
         @Override
         public void notifySession2Created(Session2Token sessionToken) {
@@ -351,6 +383,29 @@
         }
 
         @Override
+        public void dispatchMediaKeyEvent(String packageName, KeyEvent keyEvent,
+                boolean asSystemService) {
+            if (keyEvent == null || !isMediaSessionKey(keyEvent.getKeyCode())) {
+                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+                return;
+            }
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                //TODO: Dispatch key event to media session 2 if required
+                if (asSystemService) {
+                    mSessionManager.dispatchMediaKeyEventAsSystemService(keyEvent);
+                } else {
+                    mSessionManager.dispatchMediaKeyEvent(keyEvent, false);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public void registerCallback(IMediaCommunicationServiceCallback callback,
                 String packageName) throws RemoteException {
             Objects.requireNonNull(callback, "callback should not be null");
diff --git a/api/Android.bp b/api/Android.bp
index 2ea180e..66b6dba 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -90,6 +90,7 @@
         ":framework-sdkextensions{.public.api.txt}",
         ":framework-statsd{.public.api.txt}",
         ":framework-tethering{.public.api.txt}",
+        ":framework-uwb{.public.api.txt}",
         ":framework-wifi{.public.api.txt}",
         ":i18n.module.public.api{.public.api.txt}",
         ":non-updatable-current.txt",
@@ -149,6 +150,7 @@
         ":framework-sdkextensions{.public.stubs.source}",
         ":framework-statsd{.public.stubs.source}",
         ":framework-tethering{.public.stubs.source}",
+        ":framework-uwb{.public.stubs.source}",
         ":framework-wifi{.public.stubs.source}",
         ":i18n.module.public.api{.public.stubs.source}",
     ],
@@ -175,6 +177,7 @@
         ":framework-sdkextensions{.public.removed-api.txt}",
         ":framework-statsd{.public.removed-api.txt}",
         ":framework-tethering{.public.removed-api.txt}",
+        ":framework-uwb{.public.removed-api.txt}",
         ":framework-wifi{.public.removed-api.txt}",
         ":i18n.module.public.api{.public.removed-api.txt}",
         ":non-updatable-removed.txt",
@@ -215,6 +218,7 @@
         ":framework-sdkextensions{.system.api.txt}",
         ":framework-statsd{.system.api.txt}",
         ":framework-tethering{.system.api.txt}",
+        ":framework-uwb{.system.api.txt}",
         ":framework-wifi{.system.api.txt}",
         ":non-updatable-system-current.txt",
     ],
@@ -273,6 +277,7 @@
         ":framework-sdkextensions{.system.removed-api.txt}",
         ":framework-statsd{.system.removed-api.txt}",
         ":framework-tethering{.system.removed-api.txt}",
+        ":framework-uwb{.system.removed-api.txt}",
         ":framework-wifi{.system.removed-api.txt}",
         ":non-updatable-system-removed.txt",
     ],
@@ -313,6 +318,7 @@
         ":framework-sdkextensions{.module-lib.api.txt}",
         ":framework-statsd{.module-lib.api.txt}",
         ":framework-tethering{.module-lib.api.txt}",
+        ":framework-uwb{.module-lib.api.txt}",
         ":framework-wifi{.module-lib.api.txt}",
         ":non-updatable-module-lib-current.txt",
     ],
@@ -373,6 +379,7 @@
         ":framework-sdkextensions{.module-lib.removed-api.txt}",
         ":framework-statsd{.module-lib.removed-api.txt}",
         ":framework-tethering{.module-lib.removed-api.txt}",
+        ":framework-uwb{.module-lib.removed-api.txt}",
         ":framework-wifi{.module-lib.removed-api.txt}",
         ":non-updatable-module-lib-removed.txt",
     ],
@@ -491,6 +498,7 @@
         ":framework-sdkextensions.stubs{.jar}",
         ":framework-statsd.stubs{.jar}",
         ":framework-tethering.stubs{.jar}",
+        ":framework-uwb.stubs{.jar}",
         ":framework-wifi.stubs{.jar}",
         ":i18n.module.public.api.stubs{.jar}",
     ],
diff --git a/boot/Android.bp b/boot/Android.bp
index b71f9bf..049c802 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -100,6 +100,10 @@
             module: "com.android.tethering-bootclasspath-fragment",
         },
         {
+            apex: "com.android.uwb",
+            module: "com.android.uwb-bootclasspath-fragment",
+        },
+        {
             apex: "com.android.wifi",
             module: "com.android.wifi-bootclasspath-fragment",
         },
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..54fd430 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,93 @@
 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 int DYNAMIC_COLOR_COUNT = 4;
+static const char U_TEXTURE[] = "uTexture";
+static const char U_FADE[] = "uFade";
+static const char U_CROP_AREA[] = "uCropArea";
+static const char U_START_COLOR_PREFIX[] = "uStartColor";
+static const char U_END_COLOR_PREFIX[] = "uEndColor";
+static const char U_COLOR_PROGRESS[] = "uColorProgress";
+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_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    const float cWhiteMaskThreshold = 0.05f;
+    uniform sampler2D uTexture;
+    uniform float uFade;
+    uniform float uColorProgress;
+    uniform vec4 uStartColor0;
+    uniform vec4 uStartColor1;
+    uniform vec4 uStartColor2;
+    uniform vec4 uStartColor3;
+    uniform vec4 uEndColor0;
+    uniform vec4 uEndColor1;
+    uniform vec4 uEndColor2;
+    uniform vec4 uEndColor3;
+    varying highp vec2 vUv;
+    void main() {
+        vec4 mask = texture2D(uTexture, vUv);
+        float r = mask.r;
+        float g = mask.g;
+        float b = mask.b;
+        float a = mask.a;
+        // If all channels have values, render pixel as a shade of white.
+        float useWhiteMask = step(cWhiteMaskThreshold, r)
+            * step(cWhiteMaskThreshold, g)
+            * step(cWhiteMaskThreshold, b)
+            * step(cWhiteMaskThreshold, a);
+        vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress)
+                + g * mix(uStartColor1, uEndColor1, uColorProgress)
+                + b * mix(uStartColor2, uEndColor2, uColorProgress)
+                + a * mix(uStartColor3, uEndColor3, uColorProgress);
+        color = mix(color, vec4(vec3((r + g + b + a) * 0.25f), 1.0), useWhiteMask);
+        gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
+    })";
+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)) * color.a;
+    })";
+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
+};
 
 // ---------------------------------------------------------------------------
 
@@ -163,7 +249,8 @@
     requestExit();
 }
 
-static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) {
+static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo,
+    bool premultiplyAlpha) {
     AImageDecoder* decoder = nullptr;
     AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
     if (!decoder) {
@@ -177,6 +264,10 @@
     outInfo->stride = AImageDecoder_getMinimumStride(decoder);
     outInfo->flags = 0;
 
+    if (!premultiplyAlpha) {
+        AImageDecoder_setUnpremultipliedRequired(decoder, true);
+    }
+
     const size_t size = outInfo->stride * outInfo->height;
     void* pixels = malloc(size);
     int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
@@ -190,13 +281,14 @@
 }
 
 status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
-        const char* name) {
+        const char* name, bool premultiplyAlpha) {
     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
     if (asset == nullptr)
         return NO_INIT;
 
     AndroidBitmapInfo bitmapInfo;
-    void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo);
+    void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo,
+        premultiplyAlpha);
     auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
 
     asset->close();
@@ -209,7 +301,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,18 +328,19 @@
             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;
 }
 
-status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
+status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
+    bool premultiplyAlpha) {
     AndroidBitmapInfo bitmapInfo;
-    void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo);
+    void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
+        premultiplyAlpha);
     auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
 
     // FileMap memory is never released until application exit.
@@ -263,7 +355,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 +388,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;
@@ -448,16 +542,15 @@
 
         // In the case of multi-display, boot animation shows on the specified displays
         // in addition to the primary display
-        auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
-        constexpr uint32_t LAYER_STACK = 0;
-        for (auto id : physicalDisplayIds) {
+        const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+        for (const auto id : physicalDisplayIds) {
             if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
-                sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(id);
-                if (token != nullptr)
-                    t.setDisplayLayerStack(token, LAYER_STACK);
+                if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
+                    t.setDisplayLayerStack(token, ui::DEFAULT_LAYER_STACK);
+                }
             }
         }
-        t.setLayerStack(control, LAYER_STACK);
+        t.setLayerStack(control, ui::DEFAULT_LAYER_STACK);
     }
 
     t.setLayer(control, 0x40000000)
@@ -470,7 +563,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 +598,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 +690,71 @@
     }
 }
 
+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() {
+    bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
+    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
+    GLuint imageFragmentShader =
+        compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled
+            ? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE
+            : (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 +776,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 +786,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 +816,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)
@@ -766,6 +916,20 @@
     return true;
 }
 
+// Parse a color represented as a signed decimal int string.
+// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
+// If the input color string is empty, set color with values in defaultColor.
+static void parseColorDecimalString(const std::string& colorString,
+    float color[3], float defaultColor[3]) {
+    if (colorString == "") {
+        memcpy(color, defaultColor, sizeof(float) * 3);
+        return;
+    }
+    int colorInt = atoi(colorString.c_str());
+    color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
+    color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
+    color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
+}
 
 static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
     ZipEntryRO entry = zip->findEntryByName(name);
@@ -798,10 +962,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 +980,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 +1000,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 +1011,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;
     }
@@ -938,6 +1071,8 @@
         return false;
     }
     char const* s = desString.string();
+    std::string dynamicColoringPartName = "";
+    bool postDynamicColoring = false;
 
     // Parse the description file
     for (;;) {
@@ -952,11 +1087,19 @@
         int pause = 0;
         int progress = 0;
         int framesToFadeCount = 0;
+        int colorTransitionStart = 0;
+        int colorTransitionEnd = 0;
         char path[ANIM_ENTRY_NAME_MAX];
         char color[7] = "000000"; // default to black if unspecified
         char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
         char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
+        char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
         char pathType;
+        // start colors default to black if unspecified
+        char start_color_0[7] = "000000";
+        char start_color_1[7] = "000000";
+        char start_color_2[7] = "000000";
+        char start_color_3[7] = "000000";
 
         int nextReadPos;
 
@@ -971,6 +1114,18 @@
             } else {
               animation.progressEnabled = false;
             }
+        } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s %d %d",
+            dynamicColoringPartNameBuffer,
+            start_color_0, start_color_1, start_color_2, start_color_3,
+            &colorTransitionStart, &colorTransitionEnd)) {
+            animation.dynamicColoringEnabled = true;
+            parseColor(start_color_0, animation.startColors[0]);
+            parseColor(start_color_1, animation.startColors[1]);
+            parseColor(start_color_2, animation.startColors[2]);
+            parseColor(start_color_3, animation.startColors[3]);
+            animation.colorTransitionStart = colorTransitionStart;
+            animation.colorTransitionEnd = colorTransitionEnd;
+            dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
         } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
                           &pathType, &count, &pause, path, &nextReadPos) >= 4) {
             if (pathType == 'f') {
@@ -983,6 +1138,16 @@
             //       "clockPos1=%s, clockPos2=%s",
             //       pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
             Animation::Part part;
+            if (path == dynamicColoringPartName) {
+                // Part is specified to use dynamic coloring.
+                part.useDynamicColoring = true;
+                part.postDynamicColoring = false;
+                postDynamicColoring = true;
+            } else {
+                // Part does not use dynamic coloring.
+                part.useDynamicColoring = false;
+                part.postDynamicColoring =  postDynamicColoring;
+            }
             part.playUntilComplete = pathType == 'c';
             part.framesToFadeCount = framesToFadeCount;
             part.count = count;
@@ -1166,19 +1331,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 =
@@ -1193,6 +1355,10 @@
         mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
     }
 
+    if (mAnimation->dynamicColoringEnabled) {
+        initDynamicColors();
+    }
+
     playAnimation(*mAnimation);
 
     if (mTimeCheckThread != nullptr) {
@@ -1218,6 +1384,55 @@
         (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);
+}
+
+void BootAnimation::initDynamicColors() {
+    for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+        parseColorDecimalString(
+            android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
+            mAnimation->endColors[i], mAnimation->startColors[i]);
+    }
+    glUseProgram(mImageShader);
+    SLOGI("[BootAnimation] Dynamically coloring boot animation.");
+    for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+        float *startColor = mAnimation->startColors[i];
+        float *endColor = mAnimation->endColors[i];
+        glUniform4f(glGetUniformLocation(mImageShader,
+            (U_START_COLOR_PREFIX + std::to_string(i)).c_str()),
+            startColor[0], startColor[1], startColor[2], 1 /* alpha */);
+        glUniform4f(glGetUniformLocation(mImageShader,
+            (U_END_COLOR_PREFIX + std::to_string(i)).c_str()),
+            endColor[0], endColor[1], endColor[2], 1 /* alpha */);
+    }
+    mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS);
+}
+
 bool BootAnimation::playAnimation(const Animation& animation) {
     const size_t pcount = animation.parts.size();
     nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -1230,7 +1445,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) {
@@ -1261,6 +1475,19 @@
             for (size_t j=0 ; j<fcount ; j++) {
                 if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
 
+                // Color progress is
+                // - the animation progress, normalized from
+                //   [colorTransitionStart,colorTransitionEnd] to [0, 1] for the dynamic coloring
+                //   part.
+                // - 0 for parts that come before,
+                // - 1 for parts that come after.
+                float colorProgress = part.useDynamicColoring
+                    ? fmin(fmax(
+                        ((float)j - animation.colorTransitionStart) /
+                            fmax(animation.colorTransitionEnd -
+                                animation.colorTransitionStart, 1.0f), 0.0f), 1.0f)
+                    : (part.postDynamicColoring ? 1 : 0);
+
                 processDisplayEvents();
 
                 const int animationX = (mWidth - animation.width) / 2;
@@ -1272,44 +1499,38 @@
                 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);
+                    // Set decoding option to alpha unpremultiplied so that the R, G, B channels
+                    // of transparent pixels are preserved.
+                    initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
                 }
 
                 const int xc = animationX + frame.trimX;
                 const int yc = animationY + frame.trimY;
-                Region clearReg(Rect(mWidth, mHeight));
-                clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
-                if (!clearReg.isEmpty()) {
-                    Region::const_iterator head(clearReg.begin());
-                    Region::const_iterator tail(clearReg.end());
-                    glEnable(GL_SCISSOR_TEST);
-                    while (head != tail) {
-                        const Rect& r2(*head++);
-                        glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
-                        glClear(GL_COLOR_BUFFER_BIT);
-                    }
-                    glDisable(GL_SCISSOR_TEST);
-                }
+                glClear(GL_COLOR_BUFFER_BIT);
                 // 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);
+                if (animation.dynamicColoringEnabled) {
+                    glUniform1f(mImageColorProgressLocation, colorProgress);
+                }
+                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..7a597da 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 {
 
@@ -53,7 +53,7 @@
     };
 
     struct Font {
-        FileMap* map;
+        FileMap* map = nullptr;
         Texture texture;
         int char_width;
         int char_height;
@@ -62,7 +62,7 @@
     struct Animation {
         struct Frame {
             String8 name;
-            FileMap* map;
+            FileMap* map = nullptr;
             int trimX;
             int trimY;
             int trimWidth;
@@ -90,6 +90,10 @@
             uint8_t* audioData;
             int audioLength;
             Animation* animation;
+            // Controls if dynamic coloring is enabled for this part.
+            bool useDynamicColoring = false;
+            // Defines if this part is played after the dynamic coloring part.
+            bool postDynamicColoring = false;
 
             bool hasFadingPhase() const {
                 return !playUntilComplete && framesToFadeCount > 0;
@@ -105,6 +109,12 @@
         ZipFileRO* zip;
         Font clockFont;
         Font progressFont;
+         // Controls if dynamic coloring is enabled for the whole animation.
+        bool dynamicColoringEnabled = false;
+        int colorTransitionStart = 0; // Start frame of dynamic color transition.
+        int colorTransitionEnd = 0; // End frame of dynamic color transition.
+        float startColors[4][3]; // Start colors of dynamic color transition.
+        float endColors[4][3];   // End colors of dynamic color transition.
     };
 
     // All callbacks will be called from this class's internal thread.
@@ -163,9 +173,12 @@
     int displayEventCallback(int fd, int events, void* data);
     void processDisplayEvents();
 
-    status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
-    status_t initTexture(FileMap* map, int* width, int* height);
+    status_t initTexture(Texture* texture, AssetManager& asset, const char* name,
+        bool premultiplyAlpha = true);
+    status_t initTexture(FileMap* map, int* width, int* height,
+        bool premultiplyAlpha = true);
     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 +186,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&);
@@ -192,6 +206,7 @@
     void checkExit();
 
     void handleViewport(nsecs_t timestep);
+    void initDynamicColors();
 
     sp<SurfaceComposerClient>       mSession;
     AssetManager mAssets;
@@ -218,6 +233,13 @@
     sp<TimeCheckThread> mTimeCheckThread = nullptr;
     sp<Callbacks> mCallbacks;
     Animation* mAnimation = nullptr;
+    GLuint mImageShader;
+    GLuint mTextShader;
+    GLuint mImageFadeLocation;
+    GLuint mImageTextureLocation;
+    GLuint mTextCropAreaLocation;
+    GLuint mTextTextureLocation;
+    GLuint mImageColorProgressLocation;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index 1678053..64814c8 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -31,6 +31,9 @@
       + The percentage will be displayed with an x-coordinate of 'c', and a
         y-coordinate set to 1/3 of the animation height.
 
+Next, provide an optional line for dynamic coloring attributes, should dynamic coloring be used.
+See the dyanmic coloring section for format details. Skip if you don't use dynamic coloring.
+
 It is followed by a number of rows of the form:
 
     TYPE COUNT PAUSE PATH [FADE [#RGBHEX [CLOCK1 [CLOCK2]]]]
@@ -140,3 +143,35 @@
 
 Note that the ZIP archive is not actually compressed! The PNG files are already as compressed
 as they can reasonably get, and there is unlikely to be any redundancy between files.
+
+### Dynamic coloring
+
+Dynamic coloring is a render mode that draws the boot animation using a color transition.
+In this mode, instead of directly rendering the PNG images, it treats the R, G, B, A channels
+of input images as area masks of dynamic colors, which interpolates between start and end colors
+based on animation progression.
+
+To enable it, add the following line as the second line of desc.txt:
+
+    dynamic_colors PATH #RGBHEX0 #RGBHEX1 #RGBHEX2 #RGBHEX3
+
+  * **PATH:** file path of the part to apply dynamic color transition to.
+    Any part before this part will be rendered in the start colors.
+    Any part after will be rendered in the end colors.
+  * **RGBHEX1:** the first start color (masked by the R channel), specified as `#RRGGBB`.
+  * **RGBHEX2:** the second start color (masked by the G channel), specified as `#RRGGBB`.
+  * **RGBHEX3:** the thrid start color (masked by the B channel), specified as `#RRGGBB`.
+  * **RGBHEX4:** the forth start color (masked by the A channel), specified as `#RRGGBB`.
+
+The end colors will be read from the following system properties:
+
+  * persist.bootanim.color1
+  * persist.bootanim.color2
+  * persist.bootanim.color3
+  * persist.bootanim.color4
+
+When missing, the end colors will default to the start colors, effectively producing no color
+transition.
+
+Prepare your PNG images so that the R, G, B, A channels indicates the areas to draw color1,
+color2, color3 and color4 respectively.
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index a55b41b..1c82597 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -96,7 +96,7 @@
                                "--idmap-path", GetIdmapPath()});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
 
   struct stat st;
   ASSERT_EQ(stat(GetIdmapPath().c_str(), &st), 0);
@@ -123,7 +123,7 @@
                                "--idmap-path", GetIdmapPath()});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -131,24 +131,24 @@
                           "--idmap-path", GetIdmapPath()});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
 
-  ASSERT_NE(result->stdout.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
+  ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
                                              R::overlay::integer::int1)),
             std::string::npos)
-      << result->stdout;
-  ASSERT_NE(result->stdout.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
+      << result->stdout_str;
+  ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
                                              R::overlay::string::str1)),
             std::string::npos)
-      << result->stdout;
-  ASSERT_NE(result->stdout.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
+      << result->stdout_str;
+  ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
                                              R::overlay::string::str3)),
             std::string::npos)
-      << result->stdout;
-  ASSERT_NE(result->stdout.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
+      << result->stdout_str;
+  ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
                                              R::overlay::string::str4)),
             std::string::npos)
-      << result->stdout;
+      << result->stdout_str;
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -157,8 +157,8 @@
                           "--idmap-path", GetIdmapPath()});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
-  ASSERT_NE(result->stdout.find("00000000: 504d4449  magic"), std::string::npos);
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+  ASSERT_NE(result->stdout_str.find("00000000: 504d4449  magic"), std::string::npos);
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -184,7 +184,7 @@
                                "--idmap-path", GetIdmapPath()});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -194,9 +194,9 @@
                           "--resid", StringPrintf("0x%08x", R::target::string::str1)});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
-  ASSERT_NE(result->stdout.find("overlay-1"), std::string::npos);
-  ASSERT_EQ(result->stdout.find("overlay-1-sv"), std::string::npos);
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+  ASSERT_NE(result->stdout_str.find("overlay-1"), std::string::npos);
+  ASSERT_EQ(result->stdout_str.find("overlay-1-sv"), std::string::npos);
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -206,9 +206,9 @@
                           "--resid", "test.target:string/str1"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
-  ASSERT_NE(result->stdout.find("overlay-1"), std::string::npos);
-  ASSERT_EQ(result->stdout.find("overlay-1-sv"), std::string::npos);
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+  ASSERT_NE(result->stdout_str.find("overlay-1"), std::string::npos);
+  ASSERT_EQ(result->stdout_str.find("overlay-1-sv"), std::string::npos);
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -218,8 +218,8 @@
                           "--resid", "test.target:string/str1"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
-  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
-  ASSERT_NE(result->stdout.find("overlay-1-sv"), std::string::npos);
+  ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+  ASSERT_NE(result->stdout_str.find("overlay-1-sv"), std::string::npos);
 
   unlink(GetIdmapPath().c_str());
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 4c1476c..ab2cf3a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1194,6 +1194,7 @@
     field public static final int requiredFeature = 16844116; // 0x1010554
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
     field public static final int requiredNotFeature = 16844117; // 0x1010555
+    field public static final int requiredSplitTypes;
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1291,6 +1292,7 @@
     field public static final int shareInterpolator = 16843195; // 0x10101bb
     field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b
     field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
+    field public static final int sharedUserMaxSdkVersion;
     field public static final int shell = 16844180; // 0x1010594
     field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
     field public static final int shortcutId = 16844072; // 0x1010528
@@ -1328,6 +1330,7 @@
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
     field public static final int splitName = 16844105; // 0x1010549
     field public static final int splitTrack = 16843852; // 0x101044c
+    field public static final int splitTypes;
     field public static final int spotShadowAlpha = 16843967; // 0x10104bf
     field public static final int src = 16843033; // 0x1010119
     field public static final int ssp = 16843747; // 0x10103e3
@@ -2012,6 +2015,9 @@
   public static final class R.id {
     ctor public R.id();
     field public static final int accessibilityActionContextClick = 16908348; // 0x102003c
+    field public static final int accessibilityActionDragCancel;
+    field public static final int accessibilityActionDragDrop;
+    field public static final int accessibilityActionDragStart;
     field public static final int accessibilityActionHideTooltip = 16908357; // 0x1020045
     field public static final int accessibilityActionImeEnter = 16908372; // 0x1020054
     field public static final int accessibilityActionMoveWindow = 16908354; // 0x1020042
@@ -6652,7 +6658,7 @@
     method public boolean onUnbind(android.content.Intent);
     method public final void startForeground(int, android.app.Notification);
     method public final void startForeground(int, @NonNull android.app.Notification, int);
-    method public final void stopForeground(boolean);
+    method @Deprecated public final void stopForeground(boolean);
     method public final void stopForeground(int);
     method public final void stopSelf();
     method public final void stopSelf(int);
@@ -9124,6 +9130,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
@@ -9450,6 +9457,7 @@
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     field public static final int A2DP = 2; // 0x2
+    field public static final int CSIP_SET_COORDINATOR = 25; // 0x19
     field public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
     field public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
     field public static final int GATT = 7; // 0x7
@@ -9848,7 +9856,7 @@
     method @RequiresPermission(value=android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
     method public void disassociate(@NonNull String);
     method @NonNull public java.util.List<java.lang.String> getAssociations();
-    method public boolean hasNotificationAccess(android.content.ComponentName);
+    method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName);
     method public void requestNotificationAccess(android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
     method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
@@ -10679,6 +10687,8 @@
     field public static final String PERFORMANCE_HINT_SERVICE = "performance_hint";
     field public static final String POWER_SERVICE = "power";
     field public static final String PRINT_SERVICE = "print";
+    field public static final int RECEIVER_EXPORTED = 2; // 0x2
+    field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
     field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
     field public static final String RESTRICTIONS_SERVICE = "restrictions";
     field public static final String ROLE_SERVICE = "role";
@@ -12633,6 +12643,7 @@
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int);
     method @RequiresPermission(value="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS", conditional=true) public boolean setAutoRevokeWhitelisted(@NonNull String, boolean);
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
+    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setComponentEnabledSettings(@NonNull java.util.List<android.content.pm.PackageManager.ComponentEnabledSetting>);
     method public abstract void setInstallerPackageName(@NonNull String, @Nullable String);
     method public void setMimeGroup(@NonNull String, @NonNull java.util.Set<java.lang.String>);
     method public abstract void updateInstantAppCookie(@Nullable byte[]);
@@ -12829,6 +12840,16 @@
     field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
   }
 
+  public static final class PackageManager.ComponentEnabledSetting implements android.os.Parcelable {
+    ctor public PackageManager.ComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
+    method public int describeContents();
+    method @Nullable public android.content.ComponentName getComponentName();
+    method public int getEnabledFlags();
+    method public int getEnabledState();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PackageManager.ComponentEnabledSetting> CREATOR;
+  }
+
   public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
     ctor public PackageManager.NameNotFoundException();
     ctor public PackageManager.NameNotFoundException(String);
@@ -14970,7 +14991,7 @@
     method public void drawTextRun(@NonNull android.graphics.text.MeasuredText, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
     method public void drawVertices(@NonNull android.graphics.Canvas.VertexMode, int, @NonNull float[], int, @Nullable float[], int, @Nullable int[], int, @Nullable short[], int, int, @NonNull android.graphics.Paint);
     method public void enableZ();
-    method public boolean getClipBounds(@Nullable android.graphics.Rect);
+    method public boolean getClipBounds(@NonNull android.graphics.Rect);
     method @NonNull public final android.graphics.Rect getClipBounds();
     method public int getDensity();
     method @Nullable public android.graphics.DrawFilter getDrawFilter();
@@ -19909,29 +19930,32 @@
   }
 
   public class Location implements android.os.Parcelable {
-    ctor public Location(String);
-    ctor public Location(android.location.Location);
-    method public float bearingTo(android.location.Location);
-    method public static String convert(double, int);
-    method public static double convert(String);
+    ctor public Location(@Nullable String);
+    ctor public Location(@NonNull android.location.Location);
+    method public float bearingTo(@NonNull android.location.Location);
+    method @NonNull public static String convert(@FloatRange double, int);
+    method @FloatRange public static double convert(@NonNull String);
     method public int describeContents();
-    method public static void distanceBetween(double, double, double, double, float[]);
-    method public float distanceTo(android.location.Location);
-    method public void dump(android.util.Printer, String);
-    method public float getAccuracy();
-    method public double getAltitude();
-    method public float getBearing();
-    method public float getBearingAccuracyDegrees();
-    method public long getElapsedRealtimeNanos();
-    method public double getElapsedRealtimeUncertaintyNanos();
-    method public android.os.Bundle getExtras();
-    method public double getLatitude();
-    method public double getLongitude();
-    method public String getProvider();
-    method public float getSpeed();
-    method public float getSpeedAccuracyMetersPerSecond();
-    method public long getTime();
-    method public float getVerticalAccuracyMeters();
+    method public static void distanceBetween(@FloatRange double, @FloatRange double, @FloatRange double, @FloatRange double, float[]);
+    method @FloatRange public float distanceTo(@NonNull android.location.Location);
+    method public void dump(@NonNull android.util.Printer, @Nullable String);
+    method @FloatRange public float getAccuracy();
+    method @FloatRange public double getAltitude();
+    method @FloatRange(from=0.0f, to=360.0f, toInclusive=false) public float getBearing();
+    method @FloatRange public float getBearingAccuracyDegrees();
+    method @IntRange public long getElapsedRealtimeAgeMillis();
+    method @IntRange public long getElapsedRealtimeAgeMillis(@IntRange long);
+    method @IntRange public long getElapsedRealtimeMillis();
+    method @IntRange public long getElapsedRealtimeNanos();
+    method @FloatRange public double getElapsedRealtimeUncertaintyNanos();
+    method @Nullable public android.os.Bundle getExtras();
+    method @FloatRange public double getLatitude();
+    method @FloatRange public double getLongitude();
+    method @Nullable public String getProvider();
+    method @FloatRange public float getSpeed();
+    method @FloatRange public float getSpeedAccuracyMetersPerSecond();
+    method @IntRange public long getTime();
+    method @FloatRange public float getVerticalAccuracyMeters();
     method public boolean hasAccuracy();
     method public boolean hasAltitude();
     method public boolean hasBearing();
@@ -19940,30 +19964,35 @@
     method public boolean hasSpeed();
     method public boolean hasSpeedAccuracy();
     method public boolean hasVerticalAccuracy();
+    method public boolean isComplete();
     method @Deprecated public boolean isFromMockProvider();
     method public boolean isMock();
-    method @Deprecated public void removeAccuracy();
-    method @Deprecated public void removeAltitude();
-    method @Deprecated public void removeBearing();
-    method @Deprecated public void removeSpeed();
+    method public void removeAccuracy();
+    method public void removeAltitude();
+    method public void removeBearing();
+    method public void removeBearingAccuracy();
+    method public void removeElapsedRealtimeUncertaintyNanos();
+    method public void removeSpeed();
+    method public void removeSpeedAccuracy();
+    method public void removeVerticalAccuracy();
     method public void reset();
-    method public void set(android.location.Location);
-    method public void setAccuracy(float);
-    method public void setAltitude(double);
-    method public void setBearing(float);
-    method public void setBearingAccuracyDegrees(float);
-    method public void setElapsedRealtimeNanos(long);
-    method public void setElapsedRealtimeUncertaintyNanos(double);
+    method public void set(@NonNull android.location.Location);
+    method public void setAccuracy(@FloatRange float);
+    method public void setAltitude(@FloatRange double);
+    method public void setBearing(@FloatRange(fromInclusive=false, toInclusive=false) float);
+    method public void setBearingAccuracyDegrees(@FloatRange float);
+    method public void setElapsedRealtimeNanos(@IntRange long);
+    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange double);
     method public void setExtras(@Nullable android.os.Bundle);
-    method public void setLatitude(double);
-    method public void setLongitude(double);
+    method public void setLatitude(@FloatRange double);
+    method public void setLongitude(@FloatRange double);
     method public void setMock(boolean);
-    method public void setProvider(String);
-    method public void setSpeed(float);
-    method public void setSpeedAccuracyMetersPerSecond(float);
-    method public void setTime(long);
-    method public void setVerticalAccuracyMeters(float);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void setProvider(@Nullable String);
+    method public void setSpeed(@FloatRange float);
+    method public void setSpeedAccuracyMetersPerSecond(@FloatRange float);
+    method public void setTime(@IntRange long);
+    method public void setVerticalAccuracyMeters(@FloatRange float);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
     field public static final int FORMAT_DEGREES = 0; // 0x0
     field public static final int FORMAT_MINUTES = 1; // 0x1
@@ -20191,8 +20220,10 @@
     method public int getAllowedCapturePolicy();
     method public int getContentType();
     method public int getFlags();
+    method public int getSpatializationBehavior();
     method public int getUsage();
     method public int getVolumeControlStream();
+    method public boolean isContentSpatialized();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
     field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
@@ -20206,6 +20237,8 @@
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
     field @Deprecated public static final int FLAG_LOW_LATENCY = 256; // 0x100
+    field public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0; // 0x0
+    field public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1; // 0x1
     field public static final int USAGE_ALARM = 4; // 0x4
     field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
     field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -20214,9 +20247,9 @@
     field public static final int USAGE_GAME = 14; // 0xe
     field public static final int USAGE_MEDIA = 1; // 0x1
     field public static final int USAGE_NOTIFICATION = 5; // 0x5
-    field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
-    field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
-    field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+    field @Deprecated public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+    field @Deprecated public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+    field @Deprecated public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
     field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
     field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
     field public static final int USAGE_UNKNOWN = 0; // 0x0
@@ -20232,7 +20265,9 @@
     method public android.media.AudioAttributes.Builder setContentType(int);
     method public android.media.AudioAttributes.Builder setFlags(int);
     method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean);
+    method @NonNull public android.media.AudioAttributes.Builder setIsContentSpatialized(boolean);
     method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
+    method @NonNull public android.media.AudioAttributes.Builder setSpatializationBehavior(int);
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
 
@@ -20457,6 +20492,7 @@
     method public String getProperty(String);
     method public int getRingerMode();
     method @Deprecated public int getRouting(int);
+    method @Nullable public android.media.Spatializer getSpatializer();
     method public int getStreamMaxVolume(int);
     method public int getStreamMinVolume(int);
     method public int getStreamVolume(int);
@@ -22610,16 +22646,32 @@
     field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
     field public static final String KEY_WIDTH = "width";
     field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
+    field public static final String MIMETYPE_AUDIO_AAC_ELD = "audio/mp4a.40.39";
+    field public static final String MIMETYPE_AUDIO_AAC_HE_V1 = "audio/mp4a.40.05";
+    field public static final String MIMETYPE_AUDIO_AAC_HE_V2 = "audio/mp4a.40.29";
+    field public static final String MIMETYPE_AUDIO_AAC_LC = "audio/mp4a.40.02";
+    field public static final String MIMETYPE_AUDIO_AAC_XHE = "audio/mp4a.40.42";
     field public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
     field public static final String MIMETYPE_AUDIO_AC4 = "audio/ac4";
     field public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
     field public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
+    field public static final String MIMETYPE_AUDIO_DOLBY_MAT = "audio/vnd.dolby.mat";
+    field public static final String MIMETYPE_AUDIO_DOLBY_TRUEHD = "audio/vnd.dolby.mlp";
+    field public static final String MIMETYPE_AUDIO_DRA = "audio/vnd.dra";
+    field public static final String MIMETYPE_AUDIO_DTS = "audio/vnd.dts";
+    field public static final String MIMETYPE_AUDIO_DTS_HD = "audio/vnd.dts.hd";
+    field public static final String MIMETYPE_AUDIO_DTS_UHD = "audio/vnd.dts.uhd";
     field public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
     field public static final String MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc";
     field public static final String MIMETYPE_AUDIO_FLAC = "audio/flac";
     field public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
     field public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
+    field public static final String MIMETYPE_AUDIO_IEC61937 = "audio/x-iec61937";
     field public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+    field public static final String MIMETYPE_AUDIO_MPEGH_BL_L3 = "audio/mhm1.03";
+    field public static final String MIMETYPE_AUDIO_MPEGH_BL_L4 = "audio/mhm1.04";
+    field public static final String MIMETYPE_AUDIO_MPEGH_LC_L3 = "audio/mhm1.0d";
+    field public static final String MIMETYPE_AUDIO_MPEGH_LC_L4 = "audio/mhm1.0e";
     field public static final String MIMETYPE_AUDIO_MPEGH_MHA1 = "audio/mha1";
     field public static final String MIMETYPE_AUDIO_MPEGH_MHM1 = "audio/mhm1";
     field public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
@@ -23853,6 +23905,19 @@
     method public void onLoadComplete(android.media.SoundPool, int, int);
   }
 
+  public class Spatializer {
+    method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
+    method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
+    method public boolean isAvailable();
+    method public boolean isEnabled();
+    method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
+  }
+
+  public static interface Spatializer.OnSpatializerStateChangedListener {
+    method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
+    method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);
+  }
+
   public final class SubtitleData {
     ctor public SubtitleData(int, long, long, @NonNull byte[]);
     method @NonNull public byte[] getData();
@@ -25266,13 +25331,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 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();
+    method @NonNull public String getMediaKeyEventSessionPackageName();
     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 +25349,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 +31749,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 +31760,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
@@ -31825,6 +31900,7 @@
     method public void close();
     method @NonNull public static android.os.SharedMemory create(@Nullable String, int) throws android.system.ErrnoException;
     method public int describeContents();
+    method @NonNull public static android.os.SharedMemory fromFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
     method public int getSize();
     method @NonNull public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
     method @NonNull public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
@@ -34824,6 +34900,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;
@@ -39684,6 +39761,7 @@
     method public final void cancelCall();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onPlaceCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
+    method public void onRedirectionTimeout();
     method public final boolean onUnbind(@NonNull android.content.Intent);
     method public final void placeCallUnmodified();
     method public final void redirectCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
@@ -50652,6 +50730,9 @@
     method public void setPackageName(CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+    field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+    field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
     field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
     field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
     field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
@@ -50950,6 +51031,9 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COPY;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CUT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DISMISS;
+    field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_CANCEL;
+    field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_DROP;
+    field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_START;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_EXPAND;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_FOCUS;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_HIDE_TOOLTIP;
@@ -51933,7 +52017,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/module-lib-current.txt b/core/api/module-lib-current.txt
index ef9df660..b47c9cf 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -274,8 +274,9 @@
     field public static final int VPN_UID = 1016; // 0x3f8
   }
 
-  public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
-    method @NonNull public static android.os.SharedMemory create(@NonNull android.os.ParcelFileDescriptor);
+  public final class ServiceManager {
+    method public static boolean isDeclared(@NonNull String);
+    method @Nullable public static android.os.IBinder waitForDeclaredService(@NonNull String);
   }
 
   public class StatsServiceManager {
@@ -326,6 +327,11 @@
     method public static int getNumSignalStrengthLevels();
   }
 
+  public class SubscriptionManager {
+    method public void addSubscriptionInfoRecord(@NonNull String, @Nullable String, int, int);
+    method public void removeSubscriptionInfoRecord(@NonNull String, int);
+  }
+
   public class TelephonyManager {
     method @NonNull public static int[] getAllNetworkTypes();
   }
diff --git a/core/api/removed.txt b/core/api/removed.txt
index bf86422..235de26 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -213,16 +213,6 @@
 
 }
 
-package android.location {
-
-  public class Location implements android.os.Parcelable {
-    method @Deprecated public void removeBearingAccuracy();
-    method @Deprecated public void removeSpeedAccuracy();
-    method @Deprecated public void removeVerticalAccuracy();
-  }
-
-}
-
 package android.media {
 
   public final class AudioFormat implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 96c990d..1c55afb 100755
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -205,6 +205,7 @@
     field public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
     field public static final String RADIO_SCAN_WITHOUT_LOCATION = "android.permission.RADIO_SCAN_WITHOUT_LOCATION";
     field public static final String READ_ACTIVE_EMERGENCY_SESSION = "android.permission.READ_ACTIVE_EMERGENCY_SESSION";
+    field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
     field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
@@ -1969,6 +1970,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean canBondWithoutDialog();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean cancelBondProcess();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean fetchUuidsWithSdp(int);
     method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public byte[] getMetadata(int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getSimAccessPermission();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isConnected();
@@ -2106,7 +2108,9 @@
     field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
     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 COORDINATED_SET;
     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 +2121,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;
@@ -2315,6 +2320,7 @@
     method @Nullable public abstract java.io.File getPreloadsFileCache();
     method public abstract boolean isCredentialProtectedStorage();
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler);
+    method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
     method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
     method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
@@ -2352,6 +2358,7 @@
     field public static final String TETHERING_SERVICE = "tethering";
     field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
+    field public static final String UWB_SERVICE = "uwb";
     field public static final String VR_SERVICE = "vrmanager";
     field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
@@ -2434,6 +2441,7 @@
     field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
     field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
     field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
+    field public static final String EXTRA_SHOWING_ATTRIBUTION = "android.intent.extra.SHOWING_ATTRIBUTION";
     field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
     field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 67108864; // 0x4000000
@@ -2831,6 +2839,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
@@ -3275,11 +3286,13 @@
   public final class DisplayManager {
     method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
+    method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfigurationForDisplay(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
     method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
     method public android.util.Pair<float[],float[]> getMinimumBrightnessCurve();
     method public android.graphics.Point getStableDisplaySize();
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+    method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
   }
 
@@ -3632,7 +3645,7 @@
   public final class HdmiTvClient extends android.hardware.hdmi.HdmiClient {
     method public void clearTimerRecording(int, int, android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource);
     method public void deviceSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
-    method public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getDeviceList();
+    method @Deprecated public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getDeviceList();
     method public int getDeviceType();
     method public void portSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
     method public void sendMhlVendorCommand(int, int, int, byte[]);
@@ -4950,7 +4963,6 @@
   }
 
   public class Location implements android.os.Parcelable {
-    method public boolean isComplete();
     method public void makeComplete();
     method @Deprecated public void setIsFromMockProvider(boolean);
     field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
@@ -5402,6 +5414,13 @@
     field public static final android.media.RouteDiscoveryPreference EMPTY;
   }
 
+  public class Spatializer {
+    method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void addCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
+    method @NonNull @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public java.util.List<android.media.AudioDeviceAttributes> getCompatibleAudioDevices();
+    method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void removeCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
+    method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setEnabled(boolean);
+  }
+
 }
 
 package android.media.audiofx {
@@ -5420,8 +5439,6 @@
     field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
     field public static final int MIX_STATE_IDLE = 0; // 0x0
     field public static final int MIX_STATE_MIXING = 1; // 0x1
-    field public static final int MIX_TYPE_PLAYERS = 0; // 0x0
-    field public static final int MIX_TYPE_RECORDERS = 1; // 0x1
     field public static final int ROUTE_FLAG_LOOP_BACK = 2; // 0x2
     field public static final int ROUTE_FLAG_RENDER = 1; // 0x1
   }
@@ -5435,7 +5452,9 @@
   }
 
   public class AudioMixingRule {
-    method public int getTargetMixType();
+    method public int getTargetMixRole();
+    field public static final int MIX_ROLE_INJECTOR = 1; // 0x1
+    field public static final int MIX_ROLE_PLAYERS = 0; // 0x0
     field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
     field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
     field public static final int RULE_MATCH_UID = 4; // 0x4
@@ -5450,7 +5469,7 @@
     method public android.media.audiopolicy.AudioMixingRule build();
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
-    method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder setTargetMixType(int);
+    method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder setTargetMixRole(int);
   }
 
   public class AudioPolicy {
@@ -5583,11 +5602,7 @@
 
   public final class MediaSessionManager {
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventSessionChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
-    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 +5611,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 +6031,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
   }
 
@@ -6188,7 +6200,7 @@
     method public void close();
     method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
     method public int flush();
-    method public int getId();
+    method @Deprecated public int getId();
     method public long getIdLong();
     method public int read(@NonNull byte[], long, long);
     method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
@@ -6547,7 +6559,8 @@
   public static class AnalogFrontendSettings.Builder {
     method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setAftFlag(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
     method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
   }
@@ -6615,7 +6628,8 @@
     method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setBandwidth(int);
     method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setDemodOutputFormat(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setPlpSettings(@NonNull android.media.tv.tuner.frontend.Atsc3PlpSettings[]);
   }
 
@@ -6658,7 +6672,8 @@
 
   public static class AtscFrontendSettings.Builder {
     method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings build();
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int);
   }
 
@@ -6718,7 +6733,8 @@
     method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setBandwidth(int);
     method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setCodeRate(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setGuardInterval(int);
     method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setModulation(int);
     method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTimeInterleaveMode(int);
@@ -6782,7 +6798,8 @@
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setAnnex(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setBandwidth(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setInnerFec(long);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setModulation(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
@@ -6870,7 +6887,8 @@
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCanHandleDiseqcRxMessage(boolean);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
@@ -6979,7 +6997,8 @@
     method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setBandwidth(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setConstellation(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setGuardInterval(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHierarchy(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriority(boolean);
@@ -6998,9 +7017,11 @@
   }
 
   public class FrontendInfo {
-    method public int getAcquireRange();
+    method @Deprecated public int getAcquireRange();
+    method public long getAcquireRangeLong();
     method public int getExclusiveGroupId();
-    method @NonNull public android.util.Range<java.lang.Integer> getFrequencyRange();
+    method @Deprecated @NonNull public android.util.Range<java.lang.Integer> getFrequencyRange();
+    method @NonNull public android.util.Range<java.lang.Long> getFrequencyRangeLong();
     method @NonNull public android.media.tv.tuner.frontend.FrontendCapabilities getFrontendCapabilities();
     method public int getId();
     method @NonNull public int[] getStatusCapabilities();
@@ -7009,11 +7030,14 @@
   }
 
   public abstract class FrontendSettings {
-    method @IntRange(from=1) public int getEndFrequency();
-    method public int getFrequency();
+    method @Deprecated @IntRange(from=1) public int getEndFrequency();
+    method @IntRange(from=1) public long getEndFrequencyLong();
+    method @Deprecated public int getFrequency();
+    method public long getFrequencyLong();
     method public int getFrontendSpectralInversion();
     method public abstract int getType();
-    method @IntRange(from=1) public void setEndFrequency(int);
+    method @Deprecated @IntRange(from=1) public void setEndFrequency(int);
+    method @IntRange(from=1) public void setEndFrequencyLong(long);
     method public void setSpectralInversion(int);
     field public static final long FEC_11_15 = 4194304L; // 0x400000L
     field public static final long FEC_11_20 = 8388608L; // 0x800000L
@@ -7028,13 +7052,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 +7066,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
@@ -7076,7 +7100,8 @@
     method @NonNull public int[] getBers();
     method @NonNull public int[] getCodeRates();
     method @NonNull public int[] getExtendedModulations();
-    method public int getFreqOffset();
+    method @Deprecated public int getFreqOffset();
+    method public long getFreqOffsetLong();
     method public int getGuardInterval();
     method public int getHierarchy();
     method public long getInnerFec();
@@ -7192,7 +7217,8 @@
   public static class Isdbs3FrontendSettings.Builder {
     method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setCodeRate(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setModulation(int);
     method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setRolloff(int);
     method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setStreamId(int);
@@ -7235,7 +7261,8 @@
   public static class IsdbsFrontendSettings.Builder {
     method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setCodeRate(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setModulation(int);
     method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setRolloff(int);
     method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setStreamId(int);
@@ -7282,7 +7309,8 @@
     method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setBandwidth(int);
     method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setCodeRate(int);
-    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setFrequency(int);
+    method @Deprecated @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setFrequency(int);
+    method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setFrequencyLong(long);
     method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setGuardInterval(int);
     method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setMode(int);
     method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setModulation(int);
@@ -7302,7 +7330,8 @@
     method public default void onDvbcAnnexReported(int);
     method public void onDvbsStandardReported(int);
     method public void onDvbtStandardReported(int);
-    method public void onFrequenciesReported(@NonNull int[]);
+    method public default void onFrequenciesLongReported(@NonNull long[]);
+    method @Deprecated public void onFrequenciesReported(@NonNull int[]);
     method public void onGroupIdsReported(@NonNull int[]);
     method public void onHierarchyReported(int);
     method public void onInputStreamIdsReported(@NonNull int[]);
@@ -9126,6 +9155,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";
@@ -14265,148 +14295,6 @@
 
 }
 
-package android.uwb {
-
-  public final class AngleMeasurement implements android.os.Parcelable {
-    ctor public AngleMeasurement(@FloatRange(from=-3.141592653589793, to=3.141592653589793) double, @FloatRange(from=0.0, to=3.141592653589793) double, @FloatRange(from=0.0, to=1.0) double);
-    method public int describeContents();
-    method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
-    method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
-    method @FloatRange(from=-3.141592653589793, to=3.141592653589793) public double getRadians();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
-  }
-
-  public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.uwb.AngleMeasurement getAltitude();
-    method @NonNull public android.uwb.AngleMeasurement getAzimuth();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleOfArrivalMeasurement> CREATOR;
-  }
-
-  public static final class AngleOfArrivalMeasurement.Builder {
-    ctor public AngleOfArrivalMeasurement.Builder(@NonNull android.uwb.AngleMeasurement);
-    method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
-    method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
-  }
-
-  public final class DistanceMeasurement implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
-    method @FloatRange(from=0.0) public double getErrorMeters();
-    method public double getMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
-  }
-
-  public static final class DistanceMeasurement.Builder {
-    ctor public DistanceMeasurement.Builder();
-    method @NonNull public android.uwb.DistanceMeasurement build();
-    method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double);
-    method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(@FloatRange(from=0.0) double);
-    method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
-  }
-
-  public final class RangingMeasurement implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.uwb.AngleOfArrivalMeasurement getAngleOfArrivalMeasurement();
-    method @Nullable public android.uwb.DistanceMeasurement getDistanceMeasurement();
-    method public long getElapsedRealtimeNanos();
-    method @NonNull public android.uwb.UwbAddress getRemoteDeviceAddress();
-    method public int getStatus();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingMeasurement> CREATOR;
-    field public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1; // 0x1
-    field public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1; // 0xffffffff
-    field public static final int RANGING_STATUS_SUCCESS = 0; // 0x0
-  }
-
-  public static final class RangingMeasurement.Builder {
-    ctor public RangingMeasurement.Builder();
-    method @NonNull public android.uwb.RangingMeasurement build();
-    method @NonNull public android.uwb.RangingMeasurement.Builder setAngleOfArrivalMeasurement(@NonNull android.uwb.AngleOfArrivalMeasurement);
-    method @NonNull public android.uwb.RangingMeasurement.Builder setDistanceMeasurement(@NonNull android.uwb.DistanceMeasurement);
-    method @NonNull public android.uwb.RangingMeasurement.Builder setElapsedRealtimeNanos(long);
-    method @NonNull public android.uwb.RangingMeasurement.Builder setRemoteDeviceAddress(@NonNull android.uwb.UwbAddress);
-    method @NonNull public android.uwb.RangingMeasurement.Builder setStatus(int);
-  }
-
-  public final class RangingReport implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.List<android.uwb.RangingMeasurement> getMeasurements();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingReport> CREATOR;
-  }
-
-  public static final class RangingReport.Builder {
-    ctor public RangingReport.Builder();
-    method @NonNull public android.uwb.RangingReport.Builder addMeasurement(@NonNull android.uwb.RangingMeasurement);
-    method @NonNull public android.uwb.RangingReport.Builder addMeasurements(@NonNull java.util.List<android.uwb.RangingMeasurement>);
-    method @NonNull public android.uwb.RangingReport build();
-  }
-
-  public final class RangingSession implements java.lang.AutoCloseable {
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void close();
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void reconfigure(@NonNull android.os.PersistableBundle);
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void start(@NonNull android.os.PersistableBundle);
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void stop();
-  }
-
-  public static interface RangingSession.Callback {
-    method public void onClosed(int, @NonNull android.os.PersistableBundle);
-    method public void onOpenFailed(int, @NonNull android.os.PersistableBundle);
-    method public void onOpened(@NonNull android.uwb.RangingSession);
-    method public void onReconfigureFailed(int, @NonNull android.os.PersistableBundle);
-    method public void onReconfigured(@NonNull android.os.PersistableBundle);
-    method public void onReportReceived(@NonNull android.uwb.RangingReport);
-    method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
-    method public void onStarted(@NonNull android.os.PersistableBundle);
-    method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
-    method public void onStopped(int, @NonNull android.os.PersistableBundle);
-    field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
-    field public static final int REASON_GENERIC_ERROR = 4; // 0x4
-    field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
-    field public static final int REASON_MAX_SESSIONS_REACHED = 5; // 0x5
-    field public static final int REASON_PROTOCOL_SPECIFIC_ERROR = 7; // 0x7
-    field public static final int REASON_REMOTE_REQUEST = 2; // 0x2
-    field public static final int REASON_SYSTEM_POLICY = 6; // 0x6
-    field public static final int REASON_UNKNOWN = 0; // 0x0
-  }
-
-  public final class UwbAddress implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public static android.uwb.UwbAddress fromBytes(@NonNull byte[]);
-    method public int size();
-    method @NonNull public byte[] toBytes();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.UwbAddress> CREATOR;
-    field public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; // 0x8
-    field public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; // 0x2
-  }
-
-  public final class UwbManager {
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos();
-    method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo();
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.UWB_PRIVILEGED, android.Manifest.permission.UWB_RANGING}) public android.os.CancellationSignal openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
-    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
-  }
-
-  public static interface UwbManager.AdapterStateCallback {
-    method public void onStateChanged(int, int);
-    field public static final int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; // 0x1
-    field public static final int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; // 0x4
-    field public static final int STATE_CHANGED_REASON_SESSION_STARTED = 0; // 0x0
-    field public static final int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; // 0x3
-    field public static final int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; // 0x2
-    field public static final int STATE_DISABLED = 0; // 0x0
-    field public static final int STATE_ENABLED_ACTIVE = 2; // 0x2
-    field public static final int STATE_ENABLED_INACTIVE = 1; // 0x1
-  }
-
-}
-
 package android.view {
 
   public abstract class Window {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 51416b0..b8ec6fc 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1133,10 +1133,10 @@
 package android.hardware.devicestate {
 
   public final class DeviceStateManager {
-    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
+    method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
     method @NonNull public int[] getSupportedStates();
     method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
-    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+    method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
     method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
     field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
     field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
@@ -2852,6 +2852,7 @@
     method @Nullable public final android.os.IBinder getWindowContextToken();
     method public final void setWindowContextToken(@NonNull android.os.IBinder);
     field public static final int ACCESSIBILITY_TITLE_CHANGED = 33554432; // 0x2000000
+    field public static final int FLAG_SLIPPERY = 536870912; // 0x20000000
     field public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 64; // 0x40
     field public CharSequence accessibilityTitle;
     field public int privateFlags;
@@ -3244,6 +3245,7 @@
     method @NonNull public android.content.res.Configuration getConfiguration();
     method @NonNull public android.os.IBinder getFragmentToken();
     method @NonNull public android.graphics.Point getPositionInParent();
+    method public int getRunningActivityCount();
     method @NonNull public android.window.WindowContainerToken getToken();
     method public int getWindowingMode();
     method public boolean hasRunningActivity();
@@ -3338,7 +3340,7 @@
     ctor public WindowProviderService();
     method public final void attachToWindowToken(@NonNull android.os.IBinder);
     method @NonNull public int getInitialDisplayId();
-    method @Nullable public android.os.Bundle getWindowContextOptions();
+    method @CallSuper @Nullable public android.os.Bundle getWindowContextOptions();
     method public abstract int getWindowType();
   }
 
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 3a883d8..0703f7c 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).
@@ -363,6 +380,27 @@
     ],
 }
 
+java_library {
+    name: "modules-utils-statemachine",
+    srcs: [
+        "com/android/internal/util/IState.java",
+        "com/android/internal/util/State.java",
+        "com/android/internal/util/StateMachine.java",
+    ],
+    libs: [
+        "framework-annotations-lib",
+        "unsupportedappusage",
+    ],
+    sdk_version: "module_current",
+    min_sdk_version: "29",
+
+    visibility: ["//visibility:public"],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
+}
+
 filegroup {
     name: "framework-ims-common-shared-srcs",
     srcs: [
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 377edc6..a3a7b0c 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -105,12 +105,15 @@
         String statusToken);
 
     /* Returns Map<String, Integer> from package name to visibility with all values stored for given account */
+    @SuppressWarnings(value = {"untyped-collection"})
     Map getPackagesAndVisibilityForAccount(in Account account);
+    @SuppressWarnings(value = {"untyped-collection"})
     boolean addAccountExplicitlyWithVisibility(in Account account, String password, in Bundle extras,
             in Map visibility, in String opPackageName);
     boolean setAccountVisibility(in Account a, in String packageName, int newVisibility);
     int getAccountVisibility(in Account a, in String packageName);
     /* Type may be null returns Map <Account, Integer>*/
+    @SuppressWarnings(value = {"untyped-collection"})
     Map getAccountsAndVisibilityForPackage(in String packageName, in String accountType);
 
     void registerAccountListener(in String[] accountTypes, String opPackageName);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 70ee7d7..4f03b4f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8410,8 +8410,8 @@
     /**
      * @hide
      */
-    public final boolean isStopped() {
-        return mStopped;
+    public final boolean isVisibleForAutofill() {
+        return !mStopped;
     }
 
     /**
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 2efdf51..db7ab1a 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -207,7 +207,8 @@
     }
 
     /**
-     * Returns the activity token below in the same task if it belongs to the same process.
+     * Returns the non-finishing activity token below in the same task if it belongs to the same
+     * process.
      */
     @Nullable
     public IBinder getActivityTokenBelow(IBinder activityToken) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b29349e..365493de 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -771,6 +771,11 @@
         return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
     }
 
+    /** @hide Should this process state be considered in the cache? */
+    public static final boolean isProcStateCached(int procState) {
+        return procState >= PROCESS_STATE_CACHED_ACTIVITY;
+    }
+
     /** @hide Is this a foreground service type? */
     public static boolean isForegroundService(int procState) {
         return procState == PROCESS_STATE_FOREGROUND_SERVICE;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 7145c0f..b80c4b4 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -36,6 +36,7 @@
 import android.os.TransactionTooLargeException;
 import android.os.WorkSource;
 import android.util.ArraySet;
+import android.util.Pair;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -84,6 +85,18 @@
     public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
 
     /**
+     * Returns profile information in free form string in two separate strings.
+     * See AppProfiler for the output format.
+     * The output can only be used for human consumption. The format may change
+     * in the future.
+     * Do not call it frequently.
+     * @param time uptime for the cpu state
+     * @param lines lines of the cpu state should be returned
+     * @return a pair of Strings. The first is the current cpu load, the second is the cpu state.
+     */
+    public abstract Pair<String, String> getAppProfileStatsForDebugging(long time, int lines);
+
+    /**
      * Verify that calling app has access to the given provider.
      */
     public abstract String checkContentProviderAccess(String authority, @UserIdInt int userId);
@@ -412,6 +425,13 @@
     public abstract void inputDispatchingResumed(int pid);
 
     /**
+     * User tapped "wait" in the ANR dialog - reschedule the dialog to be shown again at a later
+     * time.
+     * @param data AppNotRespondingDialog.Data object
+     */
+    public abstract void rescheduleAnrDialog(Object data);
+
+    /**
      * Sends {@link android.content.Intent#ACTION_CONFIGURATION_CHANGED} with all the appropriate
      * flags.
      */
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 76f8731..d1def7e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -55,7 +55,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.SplashScreen;
 import android.window.WindowContainerToken;
 
@@ -426,7 +426,7 @@
     private IAppTransitionAnimationSpecsFuture mSpecsFuture;
     private RemoteAnimationAdapter mRemoteAnimationAdapter;
     private IBinder mLaunchCookie;
-    private IRemoteTransition mRemoteTransition;
+    private RemoteTransition mRemoteTransition;
     private boolean mOverrideTaskTransition;
     private String mSplashScreenThemeResName;
     @SplashScreen.SplashScreenStyle
@@ -1054,7 +1054,7 @@
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
     public static ActivityOptions makeRemoteAnimation(RemoteAnimationAdapter remoteAnimationAdapter,
-            IRemoteTransition remoteTransition) {
+            RemoteTransition remoteTransition) {
         final ActivityOptions opts = new ActivityOptions();
         opts.mRemoteAnimationAdapter = remoteAnimationAdapter;
         opts.mAnimationType = ANIM_REMOTE_ANIMATION;
@@ -1064,11 +1064,11 @@
 
     /**
      * Create an {@link ActivityOptions} instance that lets the application control the entire
-     * transition using a {@link IRemoteTransition}.
+     * transition using a {@link RemoteTransition}.
      * @hide
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
-    public static ActivityOptions makeRemoteTransition(IRemoteTransition remoteTransition) {
+    public static ActivityOptions makeRemoteTransition(RemoteTransition remoteTransition) {
         final ActivityOptions opts = new ActivityOptions();
         opts.mRemoteTransition = remoteTransition;
         return opts;
@@ -1181,8 +1181,7 @@
         }
         mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
         mLaunchCookie = opts.getBinder(KEY_LAUNCH_COOKIE);
-        mRemoteTransition = IRemoteTransition.Stub.asInterface(opts.getBinder(
-                KEY_REMOTE_TRANSITION));
+        mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION);
         mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
         mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME);
         mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
@@ -1348,7 +1347,7 @@
     }
 
     /** @hide */
-    public IRemoteTransition getRemoteTransition() {
+    public RemoteTransition getRemoteTransition() {
         return mRemoteTransition;
     }
 
@@ -1965,7 +1964,7 @@
             b.putBinder(KEY_LAUNCH_COOKIE, mLaunchCookie);
         }
         if (mRemoteTransition != null) {
-            b.putBinder(KEY_REMOTE_TRANSITION, mRemoteTransition.asBinder());
+            b.putParcelable(KEY_REMOTE_TRANSITION, mRemoteTransition);
         }
         if (mOverrideTaskTransition) {
             b.putBoolean(KEY_OVERRIDE_TASK_TRANSITION, mOverrideTaskTransition);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f212b6d..2e22b92 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -466,11 +466,7 @@
 
         @Override
         public int hashCode() {
-            return hashCode(authority, userId);
-        }
-
-        public static int hashCode(final String auth, final int userIdent) {
-            return ((auth != null) ? auth.hashCode() : 0) ^ userIdent;
+            return ((authority != null) ? authority.hashCode() : 0) ^ userId;
         }
     }
 
@@ -492,7 +488,7 @@
     // Note we never removes items from this map but that's okay because there are only so many
     // users and so many authorities.
     @GuardedBy("mGetProviderKeys")
-    final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>();
+    final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>();
 
     final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
         = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -530,8 +526,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 TaskFragment that embedded this activity.
-        @Nullable public IBinder mTaskFragmentToken;
+        // 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;
@@ -626,7 +623,7 @@
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
                 IBinder shareableActivityToken, boolean launchedFromBubble,
-                IBinder taskFragmentToken) {
+                IBinder initialTaskFragmentToken) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -648,7 +645,7 @@
             mActivityOptions = activityOptions;
             mPendingFixedRotationAdjustments = fixedRotationAdjustments;
             mLaunchedFromBubble = launchedFromBubble;
-            mTaskFragmentToken = taskFragmentToken;
+            mInitialTaskFragmentToken = initialTaskFragmentToken;
             init();
         }
 
@@ -6991,11 +6988,11 @@
     }
 
     private ProviderKey getGetProviderKey(String auth, int userId) {
-        final int key = ProviderKey.hashCode(auth, userId);
+        final ProviderKey key = new ProviderKey(auth, userId);
         synchronized (mGetProviderKeys) {
             ProviderKey lock = mGetProviderKeys.get(key);
             if (lock == null) {
-                lock = new ProviderKey(auth, userId);
+                lock = key;
                 mGetProviderKeys.put(key, lock);
             }
             return lock;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7e4f9b4..57de588 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2807,6 +2807,15 @@
     }
 
     @Override
+    public void setComponentEnabledSettings(List<ComponentEnabledSetting> settings) {
+        try {
+            mPM.setComponentEnabledSettings(settings, getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public int getComponentEnabledSetting(ComponentName componentName) {
         try {
             return mPM.getComponentEnabledSetting(componentName, getUserId());
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7114d73..1ab6e97 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1739,12 +1739,26 @@
     }
 
     @Override
+    public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+            IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+        return registerReceiverAsUser(receiver, UserHandle.ALL,
+                filter, broadcastPermission, scheduler, flags);
+    }
+
+    @Override
     public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
             IntentFilter filter, String broadcastPermission, Handler scheduler) {
         return registerReceiverInternal(receiver, user.getIdentifier(),
                 filter, broadcastPermission, scheduler, getOuterContext(), 0);
     }
 
+    @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+        return registerReceiverInternal(receiver, user.getIdentifier(),
+                filter, broadcastPermission, scheduler, getOuterContext(), flags);
+    }
+
     private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
             IntentFilter filter, String broadcastPermission,
             Handler scheduler, Context context, int flags) {
@@ -2260,7 +2274,7 @@
             int modeFlags) {
         try {
             return ActivityManager.getService().checkUriPermissions(uris, pid, uid, modeFlags,
-                    null);
+                    getUserId(), null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3124,6 +3138,7 @@
             mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
             mContextType = container.mContextType;
             mContentCaptureOptions = container.mContentCaptureOptions;
+            mAutofillOptions = container.mAutofillOptions;
         } else {
             mBasePackageName = packageInfo.mPackageName;
             ApplicationInfo ainfo = packageInfo.getApplicationInfo();
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 45db0f6..370031a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -749,7 +749,8 @@
          * @see #onStartActivity(Intent)
          * @hide
          */
-        public ActivityResult onStartActivity(Context who, Intent intent, Bundle options) {
+        public ActivityResult onStartActivity(@NonNull Context who, @NonNull Intent intent,
+                @NonNull Bundle options) {
             return onStartActivity(intent);
         }
 
@@ -2112,7 +2113,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 908af96..ea7fa2e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5387,8 +5387,8 @@
             contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
             // Use different highlighted colors for conversations' unread count
             if (p.mHighlightExpander) {
-                pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor);
-                textColor = Colors.flattenAlpha(bgColor, pillColor);
+                pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
+                textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor);
             }
             contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
             contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@@ -6245,8 +6245,9 @@
          *
          * @param color the color to check
          * @return true if the color has higher contrast with white than black
+         * @hide
          */
-        private static boolean isColorDark(int color) {
+        public static boolean isColorDark(int color) {
             // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
             return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
         }
@@ -12303,6 +12304,8 @@
         private int mSecondaryTextColor = COLOR_INVALID;
         private int mPrimaryAccentColor = COLOR_INVALID;
         private int mSecondaryAccentColor = COLOR_INVALID;
+        private int mTertiaryAccentColor = COLOR_INVALID;
+        private int mOnAccentTextColor = COLOR_INVALID;
         private int mErrorColor = COLOR_INVALID;
         private int mContrastColor = COLOR_INVALID;
         private int mRippleAlpha = 0x33;
@@ -12360,7 +12363,7 @@
 
             if (isColorized) {
                 if (rawColor == COLOR_DEFAULT) {
-                    int[] attrs = {R.attr.colorAccentTertiary};
+                    int[] attrs = {R.attr.colorAccentSecondary};
                     try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
                         mBackgroundColor = getColor(ta, 0, Color.WHITE);
                     }
@@ -12377,6 +12380,8 @@
                 mContrastColor = mPrimaryTextColor;
                 mPrimaryAccentColor = mPrimaryTextColor;
                 mSecondaryAccentColor = mSecondaryTextColor;
+                mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
+                mOnAccentTextColor = mBackgroundColor;
                 mErrorColor = mPrimaryTextColor;
                 mRippleAlpha = 0x33;
             } else {
@@ -12387,6 +12392,8 @@
                         R.attr.textColorSecondary,
                         R.attr.colorAccent,
                         R.attr.colorAccentSecondary,
+                        R.attr.colorAccentTertiary,
+                        R.attr.textColorOnAccent,
                         R.attr.colorError,
                         R.attr.colorControlHighlight
                 };
@@ -12397,8 +12404,10 @@
                     mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
                     mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
                     mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
-                    mErrorColor = getColor(ta, 6, COLOR_INVALID);
-                    mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
+                    mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
+                    mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
+                    mErrorColor = getColor(ta, 8, COLOR_INVALID);
+                    mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
                 }
                 mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
                         mBackgroundColor, nightMode);
@@ -12418,6 +12427,14 @@
                 if (mSecondaryAccentColor == COLOR_INVALID) {
                     mSecondaryAccentColor = mContrastColor;
                 }
+                if (mTertiaryAccentColor == COLOR_INVALID) {
+                    mTertiaryAccentColor = mContrastColor;
+                }
+                if (mOnAccentTextColor == COLOR_INVALID) {
+                    mOnAccentTextColor = ColorUtils.setAlphaComponent(
+                            ContrastColorUtil.resolvePrimaryColor(
+                                    ctx, mTertiaryAccentColor, nightMode), 0xFF);
+                }
                 if (mErrorColor == COLOR_INVALID) {
                     mErrorColor = mPrimaryTextColor;
                 }
@@ -12483,6 +12500,16 @@
             return mSecondaryAccentColor;
         }
 
+        /** @return the theme's tertiary accent color for colored UI elements. */
+        public @ColorInt int getTertiaryAccentColor() {
+            return mTertiaryAccentColor;
+        }
+
+        /** @return the theme's text color to be used on the tertiary accent color. */
+        public @ColorInt int getOnAccentTextColor() {
+            return mOnAccentTextColor;
+        }
+
         /**
          * @return the contrast-adjusted version of the color provided by the app, or the
          * primary text color when colorized.
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 1837fb8..6553b61 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -260,8 +260,6 @@
     private boolean mDemoted = false;
     private boolean mImportantConvo = false;
     private long mDeletedTime = DEFAULT_DELETION_TIME_MS;
-    // If the sound for this channel is missing, e.g. after restore.
-    private boolean mIsSoundMissing;
 
     /**
      * Creates a notification channel.
@@ -717,13 +715,6 @@
     }
 
     /**
-     * @hide
-     */
-    public boolean isSoundMissing() {
-        return mIsSoundMissing;
-    }
-
-    /**
      * Returns the audio attributes for sound played by notifications posted to this channel.
      */
     public AudioAttributes getAudioAttributes() {
@@ -1007,9 +998,8 @@
         // according to the docs because canonicalize method has to handle canonical uris as well.
         Uri canonicalizedUri = contentResolver.canonicalize(uri);
         if (canonicalizedUri == null) {
-            // We got a null because the uri in the backup does not exist here.
-            mIsSoundMissing = true;
-            return null;
+            // We got a null because the uri in the backup does not exist here, so we return default
+            return Settings.System.DEFAULT_NOTIFICATION_URI;
         }
         return contentResolver.uncanonicalize(canonicalizedUri);
     }
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 7cb1d89..0145747 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -312,29 +312,25 @@
     private static final String TAG = "Service";
 
     /**
-     * Flag for {@link #stopForeground(int)}: if set, the notification previously provided
-     * to {@link #startForeground} will be removed.  Otherwise it will remain
-     * until a later call (to {@link #startForeground(int, Notification)} or
-     * {@link #stopForeground(int)} removes it, or the service is destroyed.
+     * Selector for {@link #stopForeground(int)}: if supplied, the notification previously
+     * supplied to {@link #startForeground} will be cancelled and removed from display.
      */
     public static final int STOP_FOREGROUND_REMOVE = 1<<0;
 
     /**
-     * Flag for {@link #stopForeground(int)}: if set, the notification previously provided
-     * to {@link #startForeground} will be detached from the service.  Only makes sense
-     * when {@link #STOP_FOREGROUND_REMOVE} is <b>not</b> set -- in this case, the notification
-     * will remain shown, but be completely detached from the service and so no longer changed
-     * except through direct calls to the notification manager.
+     * Selector for {@link #stopForeground(int)}: if set, the notification previously supplied
+     * to {@link #startForeground} will be detached from the service's lifecycle.  The notification
+     * will remain shown even after the service is stopped and destroyed.
      */
     public static final int STOP_FOREGROUND_DETACH = 1<<1;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "STOP_FOREGROUND_" }, value = {
+    @IntDef(flag = false, prefix = { "STOP_FOREGROUND_" }, value = {
             STOP_FOREGROUND_REMOVE,
             STOP_FOREGROUND_DETACH
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface StopForegroundFlags {}
+    public @interface StopForegroundSelector {}
 
     public Service() {
         super(null);
@@ -387,6 +383,13 @@
      * <p>This mode makes sense for things that will be explicitly started
      * and stopped to run for arbitrary periods of time, such as a service
      * performing background music playback.
+     *
+     * <p>Since Android version {@link Build.VERSION_CODES#S}, apps
+     * targeting {@link Build.VERSION_CODES#S} or above are disallowed
+     * to start a foreground service from the background, but the restriction
+     * doesn't impact <em>restarts</em> of a sticky foreground service. However,
+     * when apps start a sticky foreground service from the background,
+     * the same restriction still applies.
      */
     public static final int START_STICKY = 1;
     
@@ -784,12 +787,16 @@
     }
 
     /**
-     * Synonym for {@link #stopForeground(int)}.
-     * @param removeNotification If true, the {@link #STOP_FOREGROUND_REMOVE} flag
-     * will be supplied.
+     * Legacy version of {@link #stopForeground(int)}.
+     * @param removeNotification If true, the {@link #STOP_FOREGROUND_REMOVE}
+     * selector will be passed to {@link #stopForeground(int)}; otherwise
+     * {@code zero} will be passed.
      * @see #stopForeground(int)
      * @see #startForeground(int, Notification)
+     *
+     * @deprecated use {@link #stopForeground(int)} instead.
      */
+    @Deprecated
     public final void stopForeground(boolean removeNotification) {
         stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : 0);
     }
@@ -800,14 +807,29 @@
      * you use {@link #stopSelf()} or related methods), just takes it out of the
      * foreground state.
      *
-     * @param flags additional behavior options.
+     * <p>If {@link #STOP_FOREGROUND_REMOVE} is supplied, the service's associated
+     * notification will be cancelled immediately.</p>
+     * <p>If {@link #STOP_FOREGROUND_DETACH} is supplied, the service's association
+     * with the notification will be severed.  If the notification had not yet been
+     * shown, due to foreground-service notification deferral policy, it is
+     * immediately posted when {@code stopForeground(STOP_FOREGROUND_DETACH)}
+     * is called.  In all cases, the notification remains shown
+     * even after this service is stopped fully and destroyed.</p>
+     * <p>If {@code zero} is passed as the argument, the result will be the legacy
+     * behavior as defined prior to Android L: the notification will remain posted until
+     * the service is fully stopped, at which time it will automatically be cancelled.</p>
+     *
+     * @param notificationBehavior the intended behavior for the service's associated
+     * notification
      * @see #startForeground(int, Notification)
+     * @see #STOP_FOREGROUND_DETACH
+     * @see #STOP_FOREGROUND_REMOVE
      */
-    public final void stopForeground(@StopForegroundFlags int flags) {
+    public final void stopForeground(@StopForegroundSelector int notificationBehavior) {
         try {
             mActivityManager.setServiceForeground(
                     new ComponentName(this, mClassName), mToken, 0, null,
-                    flags, 0);
+                    notificationBehavior, 0);
         } catch (RemoteException ex) {
         }
     }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 32ea41b..8ac8229 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -205,7 +205,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
-import android.uwb.UwbManager;
+import android.uwb.UwbFrameworkInitializer;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.WindowManager;
@@ -728,14 +728,6 @@
                 return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
             }});
 
-        registerService(Context.UWB_SERVICE, UwbManager.class,
-                new CachedServiceFetcher<UwbManager>() {
-                    @Override
-                    public UwbManager createService(ContextImpl ctx) {
-                        return UwbManager.getInstance(ctx);
-                    }
-                });
-
         registerService(Context.VIBRATOR_MANAGER_SERVICE, VibratorManager.class,
                 new CachedServiceFetcher<VibratorManager>() {
                     @Override
@@ -1486,6 +1478,7 @@
             MediaFrameworkInitializer.registerServiceWrappers();
             RoleFrameworkInitializer.registerServiceWrappers();
             SchedulingFrameworkInitializer.registerServiceWrappers();
+            UwbFrameworkInitializer.registerServiceWrappers();
         } finally {
             // If any of the above code throws, we're in a pretty bad shape and the process
             // will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 23fc6f3..31c81be 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -115,21 +115,6 @@
             "file_patterns": ["(/|^)VoiceInteract[^/]*"]
         },
         {
-            "name": "CtsContentTestCases",
-            "options": [
-                {
-                    "exclude-annotation": "androidx.test.filters.FlakyTest"
-                },
-                {
-                    "exclude-annotation": "org.junit.Ignore"
-                },
-                {
-                    "include-filter": "android.content.wm.cts"
-                }
-            ],
-            "file_patterns": ["(/|^)ContextImpl.java"]
-        },
-        {
             "name": "CtsOsTestCases",
             "options": [
                 {
@@ -163,6 +148,23 @@
             "file_patterns": ["(/|^)ContextImpl.java"]
         }
     ],
+    "presubmit-large": [
+        {
+            "name": "CtsContentTestCases",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "org.junit.Ignore"
+                },
+                {
+                    "include-filter": "android.content.wm.cts"
+                }
+            ],
+            "file_patterns": ["(/|^)ContextImpl.java"]
+        }
+    ],
     "postsubmit": [
         {
             "file_patterns": ["(/|^)ActivityThreadClientTest.java"],
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 27db25d..7102314 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3270,22 +3270,6 @@
     }
 
     /**
-     * Returns true if the Profile Challenge is available to use for the given profile user.
-     *
-     * @hide
-     */
-    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
-        if (mService != null) {
-            try {
-                return mService.isSeparateProfileChallengeAllowed(userHandle);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-        return false;
-    }
-
-    /**
      * Constant for {@link #setPasswordQuality}: the policy has no requirements
      * for the password.  Note that quality constants are ordered so that higher
      * values are more restrictive.
@@ -10596,11 +10580,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) {
@@ -13736,8 +13725,6 @@
      *
      * It is recommended that the Enterprise ID is at least 6 characters long, and no more than
      * 64 characters.
-     * This API is supposed to be called only after the boot phase is complete,
-     * throws {@link IllegalStateException} if called before boot phase is complete.
      *
      * @param enterpriseId An identifier of the organization this work profile or device is
      *                     enrolled into.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b6c48a1..4e4c2219 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -236,14 +236,14 @@
     void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearCrossProfileIntentFilters(in ComponentName admin);
 
-    boolean setPermittedAccessibilityServices(in ComponentName admin,in List packageList);
-    List getPermittedAccessibilityServices(in ComponentName admin);
-    List getPermittedAccessibilityServicesForUser(int userId);
+    boolean setPermittedAccessibilityServices(in ComponentName admin,in List<String> packageList);
+    List<String> getPermittedAccessibilityServices(in ComponentName admin);
+    List<String> getPermittedAccessibilityServicesForUser(int userId);
     boolean isAccessibilityServicePermittedByAdmin(in ComponentName admin, String packageName, int userId);
 
-    boolean setPermittedInputMethods(in ComponentName admin,in List packageList, boolean parent);
-    List getPermittedInputMethods(in ComponentName admin, boolean parent);
-    List getPermittedInputMethodsForCurrentUser();
+    boolean setPermittedInputMethods(in ComponentName admin,in List<String> packageList, boolean parent);
+    List<String> getPermittedInputMethods(in ComponentName admin, boolean parent);
+    List<String> getPermittedInputMethodsForCurrentUser();
     boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId, boolean parent);
 
     boolean setPermittedCrossProfileNotificationListeners(in ComponentName admin, in List<String> packageList);
@@ -373,8 +373,6 @@
     CharSequence getShortSupportMessageForUser(in ComponentName admin, int userHandle);
     CharSequence getLongSupportMessageForUser(in ComponentName admin, int userHandle);
 
-    boolean isSeparateProfileChallengeAllowed(int userHandle);
-
     void setOrganizationColor(in ComponentName admin, in int color);
     void setOrganizationColorForUser(in int color, in int userId);
     int getOrganizationColor(in ComponentName admin);
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index dae565e..67f631f 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -281,6 +281,32 @@
     }
 
     /**
+     * Convenience method for callers who need to indicate that some other package or
+     * some other user needs a backup pass. This can be useful in the case of groups of
+     * packages that share a uid and/or have user-specific data.
+     * <p>
+     * This method requires that the application hold the "android.permission.BACKUP"
+     * permission if the package named in the package argument does not run under the
+     * same uid as the caller. This method also requires that the application hold the
+     * "android.permission.INTERACT_ACROSS_USERS_FULL" if the user argument is not the
+     * same as the user the caller is running under.
+     * @param userId The user to back up
+     * @param packageName The package name identifying the application to back up.
+     *
+     * @hide
+     */
+    public static void dataChangedForUser(int userId, String packageName) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.dataChangedForUser(userId, packageName);
+            } catch (RemoteException e) {
+                Log.e(TAG, "dataChanged(userId,pkg) couldn't connect");
+            }
+        }
+    }
+
+    /**
      * @deprecated Applications shouldn't request a restore operation using this method. In Android
      * P and later, this method is a no-op.
      *
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/search/Query.java b/core/java/android/app/search/Query.java
index c64e107..f073b4e 100644
--- a/core/java/android/app/search/Query.java
+++ b/core/java/android/app/search/Query.java
@@ -70,7 +70,7 @@
             @NonNull Bundle extras) {
         mInput = input;
         mTimestampMillis = timestampMillis;
-        mExtras = extras == null ? extras : new Bundle();
+        mExtras = extras != null ? extras : new Bundle();
     }
 
     /**
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index a539812..186f25d 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -59,36 +59,37 @@
     }
 
     /**
-     * Get the {@link ActivityClientRecord} instance that corresponds to the provided token.
+     * Gets the {@link ActivityClientRecord} instance that corresponds to the provided token.
      * @param client Target client handler.
      * @param token Target activity token.
-     * @param includeLaunching Indicate to also find the {@link ActivityClientRecord} in launching
-     *                         activity list. It should be noted that there is no activity in
+     * @param includeLaunching Indicate to find the {@link ActivityClientRecord} in launching
+     *                         activity list.
+     *                         <p>Note that there is no {@link android.app.Activity} instance in
      *                         {@link ActivityClientRecord} from the launching activity list.
      * @return The {@link ActivityClientRecord} instance that corresponds to the provided token.
      */
     @NonNull ActivityClientRecord getActivityClientRecord(
             @NonNull ClientTransactionHandler client, IBinder token, boolean includeLaunching) {
-        ActivityClientRecord r = client.getActivityClient(token);
-        if (r != null) {
-            if (client.getActivity(token) == null) {
+        ActivityClientRecord r = null;
+        // Check launching Activity first to prevent race condition that activity instance has not
+        // yet set to ActivityClientRecord.
+        if (includeLaunching) {
+            r = client.getLaunchingActivity(token);
+        }
+        // Then if we don't want to find launching Activity or the ActivityClientRecord doesn't
+        // exist in launching Activity list. The ActivityClientRecord should have been initialized
+        // and put in the Activity list.
+        if (r == null) {
+            r = client.getActivityClient(token);
+            if (r != null && client.getActivity(token) == null) {
                 throw new IllegalArgumentException("Activity must not be null to execute "
                         + "transaction item");
             }
-            return r;
-        }
-        // The activity may not be launched yet. Fallback to check launching activity.
-        if (includeLaunching) {
-            r = client.getLaunchingActivity(token);
         }
         if (r == null) {
             throw new IllegalArgumentException("Activity client record must not be null to execute "
                     + "transaction item");
         }
-
-        // We don't need to check the activity of launching activity client records because they
-        // have not been launched yet.
-
         return r;
     }
 }
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index b723140..d61abc6 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -187,9 +187,9 @@
         mLaunchCount = stats.mLaunchCount;
         mAppLaunchCount = stats.mAppLaunchCount;
         mLastEvent = stats.mLastEvent;
-        mActivities = stats.mActivities;
-        mForegroundServices = stats.mForegroundServices;
-        mChooserCounts = stats.mChooserCounts;
+        mActivities = stats.mActivities.clone();
+        mForegroundServices = new ArrayMap<>(stats.mForegroundServices);
+        mChooserCounts = new ArrayMap<>(stats.mChooserCounts);
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2ed26a9f..2b28c11 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -64,6 +64,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -78,6 +80,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
+import java.util.WeakHashMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -715,10 +718,21 @@
     private final IBluetoothManager mManagerService;
     private final AttributionSource mAttributionSource;
 
+    // Yeah, keeping both mService and sService isn't pretty, but it's too late
+    // in the current release for a major refactoring, so we leave them both
+    // intact until this can be cleaned up in a future release
+
     @UnsupportedAppUsage
+    @GuardedBy("mServiceLock")
     private IBluetooth mService;
     private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
 
+    @GuardedBy("sServiceLock")
+    private static boolean sServiceRegistered;
+    @GuardedBy("sServiceLock")
+    private static IBluetooth sService;
+    private static final Object sServiceLock = new Object();
+
     private final Object mLock = new Object();
     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
     private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
@@ -792,19 +806,11 @@
      * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
      */
     BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
-        if (managerService == null) {
-            throw new IllegalArgumentException("bluetooth manager service is null");
-        }
-        try {
-            mServiceLock.writeLock().lock();
-            mService = managerService.registerAdapter(mManagerCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        } finally {
-            mServiceLock.writeLock().unlock();
-        }
         mManagerService = Objects.requireNonNull(managerService);
         mAttributionSource = Objects.requireNonNull(attributionSource);
+        synchronized (mServiceLock.writeLock()) {
+            mService = getBluetoothService(mManagerCallback);
+        }
         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
         mToken = new Binder(DESCRIPTOR);
     }
@@ -3162,21 +3168,16 @@
         }
     }
 
-    @SuppressLint("AndroidFrameworkBluetoothPermission")
-    private final IBluetoothManagerCallback mManagerCallback =
+    private static final IBluetoothManagerCallback sManagerCallback =
             new IBluetoothManagerCallback.Stub() {
-                @SuppressLint("AndroidFrameworkRequiresPermission")
                 public void onBluetoothServiceUp(IBluetooth bluetoothService) {
                     if (DBG) {
                         Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
                     }
 
-                    mServiceLock.writeLock().lock();
-                    mService = bluetoothService;
-                    mServiceLock.writeLock().unlock();
-
-                    synchronized (mProxyServiceStateCallbacks) {
-                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
+                    synchronized (sServiceLock) {
+                        sService = bluetoothService;
+                        for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
                             try {
                                 if (cb != null) {
                                     cb.onBluetoothServiceUp(bluetoothService);
@@ -3188,6 +3189,56 @@
                             }
                         }
                     }
+                }
+
+                public void onBluetoothServiceDown() {
+                    if (DBG) {
+                        Log.d(TAG, "onBluetoothServiceDown");
+                    }
+
+                    synchronized (sServiceLock) {
+                        sService = null;
+                        for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
+                            try {
+                                if (cb != null) {
+                                    cb.onBluetoothServiceDown();
+                                } else {
+                                    Log.d(TAG, "onBluetoothServiceDown: cb is null!");
+                                }
+                            } catch (Exception e) {
+                                Log.e(TAG, "", e);
+                            }
+                        }
+                    }
+                }
+
+                public void onBrEdrDown() {
+                    if (VDBG) {
+                        Log.i(TAG, "onBrEdrDown");
+                    }
+
+                    synchronized (sServiceLock) {
+                        for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
+                            try {
+                                if (cb != null) {
+                                    cb.onBrEdrDown();
+                                } else {
+                                    Log.d(TAG, "onBrEdrDown: cb is null!");
+                                }
+                            } catch (Exception e) {
+                                Log.e(TAG, "", e);
+                            }
+                        }
+                    }
+                }
+            };
+
+    private final IBluetoothManagerCallback mManagerCallback =
+            new IBluetoothManagerCallback.Stub() {
+                public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+                    synchronized (mServiceLock.writeLock()) {
+                        mService = bluetoothService;
+                    }
                     synchronized (mMetadataListeners) {
                         mMetadataListeners.forEach((device, pair) -> {
                             try {
@@ -3212,12 +3263,7 @@
                 }
 
                 public void onBluetoothServiceDown() {
-                    if (DBG) {
-                        Log.d(TAG, "onBluetoothServiceDown: " + mService);
-                    }
-
-                    try {
-                        mServiceLock.writeLock().lock();
+                    synchronized (mServiceLock.writeLock()) {
                         mService = null;
                         if (mLeScanClients != null) {
                             mLeScanClients.clear();
@@ -3228,29 +3274,10 @@
                         if (mBluetoothLeScanner != null) {
                             mBluetoothLeScanner.cleanup();
                         }
-                    } finally {
-                        mServiceLock.writeLock().unlock();
-                    }
-
-                    synchronized (mProxyServiceStateCallbacks) {
-                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
-                            try {
-                                if (cb != null) {
-                                    cb.onBluetoothServiceDown();
-                                } else {
-                                    Log.d(TAG, "onBluetoothServiceDown: cb is null!");
-                                }
-                            } catch (Exception e) {
-                                Log.e(TAG, "", e);
-                            }
-                        }
                     }
                 }
 
                 public void onBrEdrDown() {
-                    if (VDBG) {
-                        Log.i(TAG, "onBrEdrDown: " + mService);
-                    }
                 }
             };
 
@@ -3485,15 +3512,12 @@
 
     protected void finalize() throws Throwable {
         try {
-            mManagerService.unregisterAdapter(mManagerCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
+            removeServiceStateCallback(mManagerCallback);
         } finally {
             super.finalize();
         }
     }
 
-
     /**
      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
      * <p>Alphabetic characters must be uppercase to be valid.
@@ -3557,24 +3581,64 @@
         return mAttributionSource;
     }
 
-    private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
-            new ArrayList<IBluetoothManagerCallback>();
+    @GuardedBy("sServiceLock")
+    private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
+            new WeakHashMap<>();
+
+    /*package*/ IBluetooth getBluetoothService() {
+        synchronized (sServiceLock) {
+            if (sProxyServiceStateCallbacks.isEmpty()) {
+                throw new IllegalStateException(
+                        "Anonymous service access requires at least one lifecycle in process");
+            }
+            return sService;
+        }
+    }
 
     @UnsupportedAppUsage
     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
-        synchronized (mProxyServiceStateCallbacks) {
-            if (cb == null) {
-                Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
-            } else if (!mProxyServiceStateCallbacks.contains(cb)) {
-                mProxyServiceStateCallbacks.add(cb);
-            }
+        Objects.requireNonNull(cb);
+        synchronized (sServiceLock) {
+            sProxyServiceStateCallbacks.put(cb, null);
+            registerOrUnregisterAdapterLocked();
+            return sService;
         }
-        return mService;
     }
 
     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
-        synchronized (mProxyServiceStateCallbacks) {
-            mProxyServiceStateCallbacks.remove(cb);
+        Objects.requireNonNull(cb);
+        synchronized (sServiceLock) {
+            sProxyServiceStateCallbacks.remove(cb);
+            registerOrUnregisterAdapterLocked();
+        }
+    }
+
+    /**
+     * Handle registering (or unregistering) a single process-wide
+     * {@link IBluetoothManagerCallback} based on the presence of local
+     * {@link #sProxyServiceStateCallbacks} clients.
+     */
+    @GuardedBy("sServiceLock")
+    private void registerOrUnregisterAdapterLocked() {
+        final boolean isRegistered = sServiceRegistered;
+        final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
+
+        if (isRegistered != wantRegistered) {
+            if (wantRegistered) {
+                try {
+                    sService = mManagerService.registerAdapter(sManagerCallback);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            } else {
+                try {
+                    mManagerService.unregisterAdapter(sManagerCallback);
+                    sService = null;
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+            sServiceRegistered = wantRegistered;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index f68a8b2..eee981d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1331,7 +1331,10 @@
             if (alias == null) {
                 return getName();
             }
-            return alias;
+            return alias
+                    .replace('\t', ' ')
+                    .replace('\n', ' ')
+                    .replace('\r', ' ');
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
         }
@@ -1791,13 +1794,41 @@
     @RequiresBluetoothConnectPermission
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
     public boolean fetchUuidsWithSdp() {
+        return fetchUuidsWithSdp(TRANSPORT_AUTO);
+    }
+
+    /**
+     * Perform a service discovery on the remote device to get the UUIDs supported with the
+     * specific transport.
+     *
+     * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
+     * with the UUIDs supported by the remote end. If there is an error
+     * in getting the SDP or GATT records or if the process takes a long time, or the device
+     * is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the
+     * UUIDs that is currently present in the cache. Clients should use the {@link #getUuids}
+     * to get UUIDs if service discovery is not to be performed. If there is an ongoing bonding
+     * process, service discovery or device inquiry, the request will be queued.
+     *
+     * @param transport - provide type of transport (e.g. LE or Classic).
+     * @return False if the check fails, True if the process of initiating an ACL connection
+     * to the remote device was started or cached UUIDs will be broadcast with the specific
+     * transport.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public boolean fetchUuidsWithSdp(@Transport int transport) {
         final IBluetooth service = sService;
         if (service == null || !isBluetoothEnabled()) {
             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
             return false;
         }
         try {
-            return service.fetchRemoteUuidsWithAttribution(this, mAttributionSource);
+            return service.fetchRemoteUuidsWithAttribution(this, transport, mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
         }
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/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index c438dd3..3ea865b 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -97,12 +97,148 @@
             "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
 
     /**
+     * Intent used to broadcast group node status information.
+     *
+     * <p>This intent will have 3 extra:
+     * <ul>
+     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+     * be null if no device is active. </li>
+     * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
+     * <li> {@link #EXTRA_LE_AUDIO_GROUP_NODE_STATUS} - Group node status. </li>
+     * </ul>
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED =
+            "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED";
+
+
+    /**
+     * Intent used to broadcast group status information.
+     *
+     * <p>This intent will have 4 extra:
+     * <ul>
+     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+     * be null if no device is active. </li>
+     * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
+     * <li> {@link #EXTRA_LE_AUDIO_GROUP_STATUS} - Group status. </li>
+     * </ul>
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LE_AUDIO_GROUP_STATUS_CHANGED =
+            "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED";
+
+    /**
+     * Intent used to broadcast group audio configuration changed information.
+     *
+     * <p>This intent will have 5 extra:
+     * <ul>
+     * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
+     * <li> {@link #EXTRA_LE_AUDIO_DIRECTION} - Direction as bit mask. </li>
+     * <li> {@link #EXTRA_LE_AUDIO_SINK_LOCATION} - Sink location as per Bluetooth Assigned
+     * Numbers </li>
+     * <li> {@link #EXTRA_LE_AUDIO_SOURCE_LOCATION} - Source location as per Bluetooth Assigned
+     * Numbers </li>
+     * <li> {@link #EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS} - Available contexts for group as per
+     * Bluetooth Assigned Numbers </li>
+     * </ul>
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LE_AUDIO_CONF_CHANGED =
+            "android.bluetooth.action.LE_AUDIO_CONF_CHANGED";
+
+    /**
+     * Indicates conversation between humans as, for example, in telephony or video calls.
+     * @hide
+     */
+    public static final int CONTEXT_TYPE_COMMUNICATION = 0x0002;
+
+    /**
+     * Indicates media as, for example, in music, public radio, podcast or video soundtrack.
+     * @hide
+     */
+    public static final int CONTEXT_TYPE_MEDIA = 0x0004;
+
+    /**
      * This represents an invalid group ID.
      *
      * @hide
      */
     public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
 
+    /**
+     * Contains group id.
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_GROUP_ID =
+            "android.bluetooth.extra.LE_AUDIO_GROUP_ID";
+
+    /**
+     * Contains group node status, can be any of
+     * <p>
+     * <ul>
+     * <li> {@link #GROUP_NODE_ADDED} </li>
+     * <li> {@link #GROUP_NODE_REMOVED} </li>
+     * </ul>
+     * <p>
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_GROUP_NODE_STATUS =
+            "android.bluetooth.extra.LE_AUDIO_GROUP_NODE_STATUS";
+
+    /**
+     * Contains group status, can be any of
+     *
+     * <p>
+     * <ul>
+     * <li> {@link #GROUP_STATUS_IDLE} </li>
+     * <li> {@link #GROUP_STATUS_STREAMING} </li>
+     * <li> {@link #GROUP_STATUS_SUSPENDED} </li>
+     * <li> {@link #GROUP_STATUS_RECONFIGURED} </li>
+     * <li> {@link #GROUP_STATUS_DESTROYED} </li>
+     * </ul>
+     * <p>
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_GROUP_STATUS =
+            "android.bluetooth.extra.LE_AUDIO_GROUP_STATUS";
+
+    /**
+     * Contains bit mask for direction, bit 0 set when Sink, bit 1 set when Source.
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_DIRECTION =
+            "android.bluetooth.extra.LE_AUDIO_DIRECTION";
+
+    /**
+     * Contains source location as per Bluetooth Assigned Numbers
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_SOURCE_LOCATION =
+            "android.bluetooth.extra.LE_AUDIO_SOURCE_LOCATION";
+
+    /**
+     * Contains sink location as per Bluetooth Assigned Numbers
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_SINK_LOCATION =
+            "android.bluetooth.extra.LE_AUDIO_SINK_LOCATION";
+
+    /**
+     * Contains available context types for group as per Bluetooth Assigned Numbers
+     * @hide
+     */
+    public static final String EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS =
+            "android.bluetooth.extra.LE_AUDIO_AVAILABLE_CONTEXTS";
+
     private final BluetoothAdapter mAdapter;
     private final AttributionSource mAttributionSource;
     private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 83a272fc..0cf9f9f 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -220,12 +220,25 @@
     int VOLUME_CONTROL = 23;
 
     /**
+     * @hide
+     * Media Control Profile server
+     *
+     */
+    int MCP_SERVER = 24;
+
+    /**
+     * Coordinated Set Identification Profile set coordinator
+     *
+     */
+    int CSIP_SET_COORDINATOR = 25;
+
+    /**
      * 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 = 25;
 
     /**
      * Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index bb409d5..1655b62 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -399,7 +399,7 @@
         try {
             if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
             IBluetooth bluetoothProxy =
-                    BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+                    BluetoothAdapter.getDefaultAdapter().getBluetoothService();
             if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
             mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
                     mUuid, mPort, getSecurityFlags());
@@ -438,7 +438,7 @@
     /*package*/ int bindListen() {
         int ret;
         if (mSocketState == SocketState.CLOSED) return EBADFD;
-        IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+        IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
         if (bluetoothProxy == null) {
             Log.e(TAG, "bindListen fail, reason: bluetooth is off");
             return -1;
@@ -706,7 +706,7 @@
                 throw new IOException("socket closed");
             }
             IBluetooth bluetoothProxy =
-                    BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+                    BluetoothAdapter.getDefaultAdapter().getBluetoothService();
             if (bluetoothProxy == null) {
                 throw new IOException("Bluetooth is off");
             }
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index bc3754a..67b7252 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -174,6 +174,21 @@
     /** @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 COORDINATED_SET =
+            ParcelUuid.fromString("00001846-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/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index b99ad51..6a527a5 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemService;
 import android.app.Activity;
 import android.app.Application;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
@@ -259,7 +260,11 @@
      *
      * @param component the name of the component
      * @return whether the given component has the notification listener permission
+     *
+     * @deprecated Use
+     * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead.
      */
+    @Deprecated
     public boolean hasNotificationAccess(ComponentName component) {
         if (!checkFeaturePresent()) {
             return false;
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index f49362e..2ecd71b 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -124,6 +124,16 @@
      */
     public static final String EXTRA_ACTIVITY_OPTIONS = "android.intent.extra.ACTIVITY_OPTIONS";
 
+    /**
+     * An instance id used for logging.
+     * <p>
+     * Type: {@link com.android.internal.logging.InstanceId}
+     * </p>
+     * @hide
+     */
+    public static final String EXTRA_LOGGING_INSTANCE_ID =
+            "android.intent.extra.LOGGING_INSTANCE_ID";
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value =
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/Context.java b/core/java/android/content/Context.java
index ac88c7b..1df4b20 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -534,8 +534,8 @@
                     | Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
-            RECEIVER_VISIBLE_TO_INSTANT_APPS
+    @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
+            RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface RegisterReceiverFlags {}
@@ -546,6 +546,18 @@
     public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x1;
 
     /**
+     * Flag for {@link #registerReceiver}: The receiver can receive broadcasts from other Apps.
+     * Has the same behavior as marking a statically registered receiver with "exported=true"
+     */
+    public static final int RECEIVER_EXPORTED = 0x2;
+
+    /**
+     * Flag for {@link #registerReceiver}: The receiver cannot receive broadcasts from other Apps.
+     * Has the same behavior as marking a statically registered receiver with "exported=false"
+     */
+    public static final int RECEIVER_NOT_EXPORTED = 0x4;
+
+    /**
      * Returns an AssetManager instance for the application's package.
      * <p>
      * <strong>Note:</strong> Implementations of this method should return
@@ -2989,8 +3001,12 @@
      *
      * @param receiver The BroadcastReceiver to handle the broadcast.
      * @param filter Selects the Intent broadcasts to be received.
-     * @param flags Additional options for the receiver. May be 0 or
-     *      {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
+     * @param flags Additional options for the receiver. As of
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+     * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+     *            for protected broadcasts, and may additionally specify
+     *            {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
+     *            specified.
      *
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or null if there are none.
@@ -3062,8 +3078,12 @@
      *      no permission is required.
      * @param scheduler Handler identifying the thread that will receive
      *      the Intent.  If null, the main thread of the process will be used.
-     * @param flags Additional options for the receiver. May be 0 or
-     *      {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
+     * @param flags Additional options for the receiver. As of
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+     * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+     *            for protected broadcasts, and may additionally specify
+     *            {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
+     *            specified.
      *
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or null if there are none.
@@ -3110,6 +3130,42 @@
     }
 
     /**
+     * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)}
+     * but this receiver will receive broadcasts that are sent to all users. The receiver can
+     * use {@link BroadcastReceiver#getSendingUser} to determine on which user the broadcast
+     * was sent.
+     *
+     * @param receiver The BroadcastReceiver to handle the broadcast.
+     * @param filter Selects the Intent broadcasts to be received.
+     * @param broadcastPermission String naming a permissions that a
+     *      broadcaster must hold in order to send an Intent to you. If {@code null},
+     *      no permission is required.
+     * @param scheduler Handler identifying the thread that will receive
+     *      the Intent. If {@code null}, the main thread of the process will be used.
+     * @param flags Additional options for the receiver. As of
+     *      {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+     *      {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
+     *      registered for protected broadcasts
+     *
+     * @return The first sticky intent found that matches <var>filter</var>,
+     *         or {@code null} if there are none.
+     *
+     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)
+     * @see #sendBroadcast
+     * @see #unregisterReceiver
+     * @hide
+     */
+    @SuppressLint("IntentBuilderName")
+    @Nullable
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    @SystemApi
+    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+            @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler, @RegisterReceiverFlags int flags) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * @hide
      * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
      * but for a specific user.  This receiver will receiver broadcasts that
@@ -3140,6 +3196,41 @@
             @Nullable Handler scheduler);
 
     /**
+     * @hide
+     * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)
+     * but for a specific user.  This receiver will receiver broadcasts that
+     * are sent to the requested user.
+     *
+     * @param receiver The BroadcastReceiver to handle the broadcast.
+     * @param user UserHandle to send the intent to.
+     * @param filter Selects the Intent broadcasts to be received.
+     * @param broadcastPermission String naming a permissions that a
+     *      broadcaster must hold in order to send an Intent to you.  If null,
+     *      no permission is required.
+     * @param scheduler Handler identifying the thread that will receive
+     *      the Intent.  If null, the main thread of the process will be used.
+     * @param flags Additional options for the receiver. As of
+     *      {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+     *      {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
+     *      registered for protected broadcasts
+     *
+     * @return The first sticky intent found that matches <var>filter</var>,
+     *         or null if there are none.
+     *
+     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)
+     * @see #sendBroadcast
+     * @see #unregisterReceiver
+     */
+    @SuppressWarnings("HiddenAbstractMethod")
+    @SuppressLint("IntentBuilderName")
+    @Nullable
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    @UnsupportedAppUsage
+    public abstract Intent registerReceiverAsUser(BroadcastReceiver receiver,
+            UserHandle user, IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler, @RegisterReceiverFlags int flags);
+
+    /**
      * Unregister a previously registered BroadcastReceiver.  <em>All</em>
      * filters that have been registered for this BroadcastReceiver will be
      * removed.
@@ -3195,7 +3286,7 @@
      * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O}
      * or higher are not allowed to start background services from the background.
      * See
-     * <a href="{@docRoot}/about/versions/oreo/background">
+     * <a href="/about/versions/oreo/background">
      * Background Execution Limits</a>
      * for more details.
      *
@@ -3204,7 +3295,7 @@
      * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
      * or higher are not allowed to start foreground services from the background.
      * See
-     * <a href="{@docRoot}/about/versions/12/behavior-changes-12">
+     * <a href="/about/versions/12/behavior-changes-12">
      * Behavior changes: Apps targeting Android 12
      * </a>
      * for more details.
@@ -3258,7 +3349,7 @@
      * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
      * or higher are not allowed to start foreground services from the background.
      * See
-     * <a href="{@docRoot}/about/versions/12/behavior-changes-12">
+     * <a href="/about/versions/12/behavior-changes-12">
      * Behavior changes: Apps targeting Android 12
      * </a>
      * for more details.
@@ -3301,6 +3392,12 @@
      * to startService() are not counted -- this stops the service no matter
      * how many times it was started.
      *
+     * <p>If the service is running as a foreground service when it is
+     * stopped, its associated notification will be removed.  To avoid this,
+     * apps can use {@link android.app.Service#stopForeground(int)
+     * stopForeground(STOP_FOREGROUND_DETACH)} to decouple the notification
+     * from the service's lifecycle before stopping it.</p>
+     *
      * <p>Note that if a stopped service still has {@link ServiceConnection}
      * objects bound to it with the {@link #BIND_AUTO_CREATE} set, it will
      * not be destroyed until all of these bindings are removed.  See
@@ -4464,11 +4561,11 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
-     * android.media.MediaTranscodeManager} for transcoding media.
+     * android.media.MediaTranscodingManager} for transcoding media.
      *
      * @hide
      * @see #getSystemService(String)
-     * @see android.media.MediaTranscodeManager
+     * @see android.media.MediaTranscodingManager
      */
     @SystemApi
     public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
@@ -5606,6 +5703,7 @@
      * @see #getSystemService(String)
      * @hide
      */
+    @SystemApi
     public static final String UWB_SERVICE = "uwb";
 
     /**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 6324d0e..3a02004 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -756,6 +756,16 @@
 
     /** @hide */
     @Override
+    @Nullable
+    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+            @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler, int flags) {
+        return mBase.registerReceiverForAllUsers(receiver, filter, broadcastPermission,
+                scheduler, flags);
+    }
+
+    /** @hide */
+    @Override
     @UnsupportedAppUsage
     public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
             IntentFilter filter, @Nullable String broadcastPermission,
@@ -764,6 +774,16 @@
                 scheduler);
     }
 
+    /** @hide */
+    @Override
+    @UnsupportedAppUsage
+    public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler, int flags) {
+        return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                scheduler, flags);
+    }
+
     @Override
     public void unregisterReceiver(BroadcastReceiver receiver) {
         mBase.unregisterReceiver(receiver);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 846349d..335e703 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -30,6 +30,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.bluetooth.BluetoothDevice;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -2738,6 +2739,22 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
+    /**
+     * Broadcast Action: One of the suspend conditions have been modified for the packages.
+     * <p>Includes the following extras:
+     * <ul>
+     * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been modified
+     * <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been modified
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system. It is only sent to registered receivers.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGES_SUSPENSION_CHANGED =
+            "android.intent.action.PACKAGES_SUSPENSION_CHANGED";
 
     /**
      * Broadcast Action: Distracting packages have been changed.
@@ -4917,6 +4934,12 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_CAR_LAUNCHER = "android.intent.category.CAR_LAUNCHER";
     /**
+     * Used to indicate that the activity can be used in communal mode.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_COMMUNAL_MODE = "android.intent.category.COMMUNAL_MODE";
+    /**
      * Indicates a Leanback settings activity to be displayed in the Leanback launcher.
      * @hide
      */
@@ -5386,6 +5409,22 @@
     public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
 
     /**
+     * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD},
+     * that specifies whether the system displayed attribution information in the
+     * permission usage system UI for the chosen entry.
+     *
+     * <p> The extra can only be true if application has specified attributionsAreUserVisible
+     * in its manifest. </p>
+     *
+     * <p> Applications can use this extra to improve their permission usage explanation
+     * experience. </p>
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SHOWING_ATTRIBUTION =
+            "android.intent.extra.SHOWING_ATTRIBUTION";
+
+    /**
      * An Intent[] describing additional, alternate choices you would like shown with
      * {@link #ACTION_CHOOSER}.
      *
@@ -6993,6 +7032,7 @@
     private int mContentUserHint = UserHandle.USER_CURRENT;
     /** Token to track instant app launches. Local only; do not copy cross-process. */
     private String mLaunchToken;
+    private Intent mOriginalIntent; // Used for the experimental "component alias" feature.
 
     // ---------------------------------------------------------------------
 
@@ -7029,6 +7069,7 @@
         this.mIdentifier = o.mIdentifier;
         this.mPackage = o.mPackage;
         this.mComponent = o.mComponent;
+        this.mOriginalIntent = o.mOriginalIntent;
 
         if (o.mCategories != null) {
             this.mCategories = new ArraySet<>(o.mCategories);
@@ -8193,6 +8234,22 @@
         return mType;
     }
 
+
+    /**
+     * @hide For the experimental component alias feature. Do not use, unless you know what it is.
+     */
+    @Nullable
+    public Intent getOriginalIntent() {
+        return mOriginalIntent;
+    }
+
+    /**
+     * @hide For the experimental component alias feature. Do not use, unless you know what it is.
+     */
+    public void setOriginalIntent(@Nullable Intent originalIntent) {
+        mOriginalIntent = originalIntent;
+    }
+
     /**
      * Return the MIME data type of this intent.  If the type field is
      * explicitly set, that is simply returned.  Otherwise, if the data is set,
@@ -8247,7 +8304,10 @@
      *         needed.
      */
     public @Nullable String resolveTypeIfNeeded(@NonNull ContentResolver resolver) {
-        if (mComponent != null) {
+        // Match logic in PackageManagerService#applyEnforceIntentFilterMatching(...)
+        if (mComponent != null && (Process.myUid() == Process.ROOT_UID
+                || Process.myUid() == Process.SYSTEM_UID
+                || mComponent.getPackageName().equals(ActivityThread.currentPackageName()))) {
             return mType;
         }
         return resolveType(resolver);
@@ -10838,6 +10898,11 @@
             mSelector.toShortString(b, secure, comp, extras, clip);
             b.append("}");
         }
+        if (mOriginalIntent != null) {
+            b.append(" org={");
+            mOriginalIntent.toShortString(b, secure, comp, extras, clip);
+            b.append("}");
+        }
     }
 
     /** @hide */
@@ -11133,6 +11198,13 @@
         }
         out.writeInt(mContentUserHint);
         out.writeBundle(mExtras);
+
+        if (mOriginalIntent != null) {
+            out.writeInt(1);
+            mOriginalIntent.writeToParcel(out, flags);
+        } else {
+            out.writeInt(0);
+        }
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<Intent> CREATOR
@@ -11186,6 +11258,9 @@
         }
         mContentUserHint = in.readInt();
         mExtras = in.readBundle();
+        if (in.readInt() != 0) {
+            mOriginalIntent = new Intent(in);
+        }
     }
 
     /**
@@ -11410,6 +11485,9 @@
         if (mClipData != null) {
             mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
         }
+        if (mOriginalIntent != null) {
+            mOriginalIntent.prepareToLeaveProcess(leavingPackage);
+        }
 
         if (mExtras != null && !mExtras.isParcelled()) {
             final Object intent = mExtras.get(Intent.EXTRA_INTENT);
@@ -11505,6 +11583,9 @@
         if (mClipData != null) {
             mClipData.prepareToEnterProcess(source);
         }
+        if (mOriginalIntent != null) {
+            mOriginalIntent.prepareToEnterProcess(false, source);
+        }
 
         if (mContentUserHint != UserHandle.USER_CURRENT) {
             if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java
index a04fbd1..b6cdd96 100644
--- a/core/java/android/content/LocusId.java
+++ b/core/java/android/content/LocusId.java
@@ -62,6 +62,9 @@
  *   <li>Configuring your app to launch the chat conversation through the
  *   {@link Intent#ACTION_VIEW_LOCUS} intent.
  * </ul>
+ *
+ * NOTE: The LocusId is only used by an on-device intelligence service provided by the Android
+ * System, see {@link ContentCaptureManager} for more details.
  */
 public final class LocusId implements Parcelable {
 
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 8ad1349..c7f92c9 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -1,12 +1,14 @@
 # Remain no owner because multiple modules may touch this file.
 per-file Context.java = *
 per-file ContextWrapper.java = *
-per-file Content* = varunshah@google.com, omakoto@google.com, jsharkey@google.com
+per-file Content* = file:/services/core/java/com/android/server/am/OWNERS
 per-file IntentFilter.java = toddke@google.com
 per-file IntentFilter.java = patb@google.com
+per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file Intent.java = toddke@google.com
 per-file Intent.java = patb@google.com
 per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Intent.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
 per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
 per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
index 614143e..7f1d0d1 100644
--- a/core/java/android/content/TEST_MAPPING
+++ b/core/java/android/content/TEST_MAPPING
@@ -1,21 +1,6 @@
 {
   "presubmit": [
     {
-      "name": "CtsContentTestCases",
-      "options": [
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-          "include-filter": "android.content.wm.cts"
-        }
-      ],
-      "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
-    },
-    {
       "name": "CtsOsTestCases",
       "options": [
         {
@@ -51,5 +36,22 @@
       ],
       "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java", "(/|^)ComponentCallbacksController.java"]
     }
+  ],
+  "presubmit-large": [
+    {
+      "name": "CtsContentTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.content.wm.cts"
+        }
+      ],
+      "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+    }
   ]
 }
\ No newline at end of file
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index e319d2c..a0f3d7a 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -40,7 +40,7 @@
      *         requested user, an empty map is returned.
      */
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
-    Map getAllOverlays(in int userId);
+    Map<String, List<OverlayInfo>> getAllOverlays(in int userId);
 
     /**
      * Returns information about all overlays for the given target package for
@@ -52,7 +52,7 @@
      * @return A list of OverlayInfo objects; if no overlays exist for the
      *         requested package, an empty list is returned.
      */
-    List getOverlayInfosForTarget(in String targetPackageName, in int userId);
+    List<OverlayInfo> getOverlayInfosForTarget(in String targetPackageName, in int userId);
 
     /**
      * Returns information about the overlay with the given package name for the
diff --git a/core/java/android/content/om/TEST_MAPPING b/core/java/android/content/om/TEST_MAPPING
index d8f8854..6185cf6 100644
--- a/core/java/android/content/om/TEST_MAPPING
+++ b/core/java/android/content/om/TEST_MAPPING
@@ -21,7 +21,9 @@
           "include-filter": "android.appsecurity.cts.OverlayHostTest"
         }
       ]
-    },
+    }
+  ],
+  "presubmit-large": [
     {
       "name": "CtsContentTestCases",
       "options": [
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 95c5612..172a51a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.TestApi;
 import android.app.Activity;
@@ -1368,8 +1369,8 @@
     }
 
     /** @hide */
-    public void setMaxAspectRatio(float maxAspectRatio) {
-        this.mMaxAspectRatio = maxAspectRatio;
+    public void setMaxAspectRatio(@FloatRange(from = 0f) float maxAspectRatio) {
+        this.mMaxAspectRatio = maxAspectRatio >= 0f ? maxAspectRatio : 0f;
     }
 
     /** @hide */
@@ -1378,8 +1379,8 @@
     }
 
     /** @hide */
-    public void setMinAspectRatio(float minAspectRatio) {
-        this.mMinAspectRatio = minAspectRatio;
+    public void setMinAspectRatio(@FloatRange(from = 0f) float minAspectRatio) {
+        this.mMinAspectRatio = minAspectRatio >= 0f ? minAspectRatio : 0f;
     }
 
     /**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a4ff18a..86030fd 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -40,6 +40,7 @@
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ComponentEnabledSetting;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
 import android.content.pm.PermissionGroupInfo;
@@ -359,6 +360,11 @@
             in int newState, in int flags, int userId);
 
     /**
+     * As per {@link android.content.pm.PackageManager#setComponentEnabledSettings}.
+     */
+    void setComponentEnabledSettings(in List<ComponentEnabledSetting> settings, int userId);
+
+    /**
      * As per {@link android.content.pm.PackageManager#getComponentEnabledSetting}.
      */
     @UnsupportedAppUsage
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/PackageManager.aidl b/core/java/android/content/pm/PackageManager.aidl
index 31365a1..87bfa54 100644
--- a/core/java/android/content/pm/PackageManager.aidl
+++ b/core/java/android/content/pm/PackageManager.aidl
@@ -18,3 +18,4 @@
 package android.content.pm;
 
 parcelable PackageManager.Property;
+parcelable PackageManager.ComponentEnabledSetting;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 08afb4f..31b9c30 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -83,6 +83,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DataClass;
 
 import dalvik.system.VMRuntime;
 
@@ -380,6 +381,219 @@
     }
 
     /**
+     * The class containing the enabled setting of a package component.
+     * <p>
+     * This is used by the {@link #setComponentEnabledSettings(List)} to support the batch updates
+     * of the enabled settings of components.
+     *
+     * @see #setComponentEnabledSettings(List)
+     */
+    @DataClass(genConstructor = false)
+    public static final class ComponentEnabledSetting implements Parcelable {
+        /**
+         * The package name of the application to enable the setting.
+         */
+        private final @Nullable String mPackageName;
+
+        /**
+         * The component name of the application to enable the setting.
+         */
+        private final @Nullable ComponentName mComponentName;
+
+        /**
+         * The new enabled state
+         */
+        private final @EnabledState int mEnabledState;
+
+        /**
+         * The optional behavior flag
+         */
+        private final @EnabledFlags int mEnabledFlags;
+
+        /**
+         * Create an instance of the ComponentEnabledSetting for the component level's enabled
+         * setting update.
+         *
+         * @param componentName The component name to update the enabled setting.
+         * @param newState The new enabled state.
+         * @param flags The optional behavior flags.
+         */
+        public ComponentEnabledSetting(@NonNull ComponentName componentName,
+                @EnabledState int newState, @EnabledFlags int flags) {
+            Objects.nonNull(componentName);
+            mPackageName = null;
+            mComponentName = componentName;
+            mEnabledState = newState;
+            mEnabledFlags = flags;
+        }
+
+        /**
+         * Create an instance of the ComponentEnabledSetting for the application level's enabled
+         * setting update.
+         *
+         * @param packageName The package name to update the enabled setting.
+         * @param newState The new enabled state.
+         * @param flags The optional behavior flags.
+         * @hide
+         */
+        public ComponentEnabledSetting(@NonNull String packageName,
+                @EnabledState int newState, @EnabledFlags int flags) {
+            Objects.nonNull(packageName);
+            mPackageName = packageName;
+            mComponentName = null;
+            mEnabledState = newState;
+            mEnabledFlags = flags;
+        }
+
+        /**
+         * Returns the package name of the setting.
+         *
+         * @return the package name.
+         * @hide
+         */
+        public @NonNull String getPackageName() {
+            if (isComponent()) {
+                return mComponentName.getPackageName();
+            }
+            return mPackageName;
+        }
+
+        /**
+         * Returns the component class name of the setting.
+         *
+         * @return the class name.
+         * @hide
+         */
+        public @Nullable String getClassName() {
+            if (isComponent()) {
+                return mComponentName.getClassName();
+            }
+            return null;
+        }
+
+        /**
+         * Whether or not this is for the component level's enabled setting update.
+         *
+         * @return {@code true} if it's the component level enabled setting update.
+         * @hide
+         */
+        public boolean isComponent() {
+            return mComponentName != null;
+        }
+
+
+
+        // Code below generated by codegen v1.0.23.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageManager.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * The component name of the application to enable the setting.
+         */
+        @DataClass.Generated.Member
+        public @Nullable ComponentName getComponentName() {
+            return mComponentName;
+        }
+
+        /**
+         * The new enabled state
+         */
+        @DataClass.Generated.Member
+        public @EnabledState int getEnabledState() {
+            return mEnabledState;
+        }
+
+        /**
+         * The optional behavior flag
+         */
+        @DataClass.Generated.Member
+        public @EnabledFlags int getEnabledFlags() {
+            return mEnabledFlags;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            byte flg = 0;
+            if (mPackageName != null) flg |= 0x1;
+            if (mComponentName != null) flg |= 0x2;
+            dest.writeByte(flg);
+            if (mPackageName != null) dest.writeString(mPackageName);
+            if (mComponentName != null) dest.writeTypedObject(mComponentName, flags);
+            dest.writeInt(mEnabledState);
+            dest.writeInt(mEnabledFlags);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ ComponentEnabledSetting(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            String packageName = (flg & 0x1) == 0 ? null : in.readString();
+            ComponentName componentName = (flg & 0x2) == 0 ? null : (ComponentName) in.readTypedObject(ComponentName.CREATOR);
+            int enabledState = in.readInt();
+            int enabledFlags = in.readInt();
+
+            this.mPackageName = packageName;
+            this.mComponentName = componentName;
+            this.mEnabledState = enabledState;
+            com.android.internal.util.AnnotationValidations.validate(
+                    EnabledState.class, null, mEnabledState);
+            this.mEnabledFlags = enabledFlags;
+            com.android.internal.util.AnnotationValidations.validate(
+                    EnabledFlags.class, null, mEnabledFlags);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<ComponentEnabledSetting> CREATOR
+                = new Parcelable.Creator<ComponentEnabledSetting>() {
+            @Override
+            public ComponentEnabledSetting[] newArray(int size) {
+                return new ComponentEnabledSetting[size];
+            }
+
+            @Override
+            public ComponentEnabledSetting createFromParcel(@NonNull Parcel in) {
+                return new ComponentEnabledSetting(in);
+            }
+        };
+
+        @DataClass.Generated(
+                time = 1628668290863L,
+                codegenVersion = "1.0.23",
+                sourceFile = "frameworks/base/core/java/android/content/pm/PackageManager.java",
+                inputSignatures = "private final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable android.content.ComponentName mComponentName\nprivate final @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate final @android.content.pm.PackageManager.EnabledFlags int mEnabledFlags\npublic @android.annotation.NonNull java.lang.String getPackageName()\npublic @android.annotation.Nullable java.lang.String getClassName()\npublic  boolean isComponent()\nclass ComponentEnabledSetting extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    /**
      * Listener for changes in permissions granted to a UID.
      *
      * @hide
@@ -1053,26 +1267,36 @@
 
     /** @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 will remain unchanged during rollback.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ROLLBACK_DATA_POLICY_RETAIN = 2;
 
     /** @hide */
     @IntDef(flag = true, prefix = { "INSTALL_" }, value = {
@@ -7664,6 +7888,9 @@
      * This setting will override any enabled state which may have been set by the component in its
      * manifest.
      *
+     * <p>Consider using {@link #setComponentEnabledSettings(List)} if multiple components need to
+     * be updated atomically.
+     *
      * @param componentName The component to enable
      * @param newState The new enabled state for the component.
      * @param flags Optional behavior flags.
@@ -7674,6 +7901,32 @@
             @EnabledState int newState, @EnabledFlags int flags);
 
     /**
+     * Set the enabled settings for package components such as activities, receivers, services and
+     * providers. This setting will override any enabled state which may have been set by the
+     * component in its manifest.
+     *
+     * <p>This api accepts a list of component changes, and applies them all atomically. The
+     * application can use this api if components have dependencies and need to be updated
+     * atomically.
+     *
+     * <p>The permission is not required if target components are running under the same uid with
+     * the caller.
+     *
+     * @param settings The list of component enabled settings to update. Note that an
+     *                 {@link IllegalArgumentException} is thrown if the duplicated component name
+     *                 is in the list or there's a conflict {@link #DONT_KILL_APP} flag between
+     *                 different components in the same package.
+     *
+     * @see #setComponentEnabledSetting(ComponentName, int, int)
+     */
+    @RequiresPermission(value = android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
+            conditional = true)
+    public void setComponentEnabledSettings(@NonNull List<ComponentEnabledSetting> settings) {
+        throw new UnsupportedOperationException("setComponentEnabledSettings not implemented"
+                + "in subclass");
+    }
+
+    /**
      * Return the enabled setting for a package component (activity,
      * receiver, service, provider).  This returns the last value set by
      * {@link #setComponentEnabledSetting(ComponentName, int, int)}; in most
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bed0383..1b34d9b 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);
@@ -8029,12 +7971,9 @@
         }
         ai.enabledSetting = state.enabled;
         if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
-            ai.category = state.categoryHint;
-        }
-        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
         }
-        ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+        ai.seInfoUser = SELinuxUtil.getSeinfoUser(state);
         final OverlayPaths overlayPaths = state.getAllOverlayPaths();
         if (overlayPaths != null) {
             ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]);
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 84317b3..3fb1999 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -48,20 +48,26 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Per-user state information about a package.
  * @hide
  */
-public class PackageUserState {
+public class PackageUserState implements android.content.pm.pkg.PackageUserState {
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "PackageUserState";
 
@@ -77,7 +83,7 @@
     public boolean virtualPreload;
     public int enabled;
     public String lastDisableAppCaller;
-    public int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
+    @PackageManager.InstallReason
     public int installReason;
     public @PackageManager.UninstallReason int uninstallReason;
     public String harmfulAppWarning;
@@ -118,7 +124,6 @@
         virtualPreload = o.virtualPreload;
         enabled = o.enabled;
         lastDisableAppCaller = o.lastDisableAppCaller;
-        categoryHint = o.categoryHint;
         installReason = o.installReason;
         uninstallReason = o.uninstallReason;
         disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
@@ -134,16 +139,6 @@
         splashScreenTheme = o.splashScreenTheme;
     }
 
-    @Nullable
-    public OverlayPaths getOverlayPaths() {
-        return overlayPaths;
-    }
-
-    @Nullable
-    public Map<String, OverlayPaths> getSharedLibraryOverlayPaths() {
-        return sharedLibraryOverlayPaths;
-    }
-
     /**
      * Sets the path of overlays currently enabled for this package and user combination.
      * @return true if the path contents differ than what they were previously
@@ -443,9 +438,6 @@
                         && !lastDisableAppCaller.equals(oldState.lastDisableAppCaller))) {
             return false;
         }
-        if (categoryHint != oldState.categoryHint) {
-            return false;
-        }
         if (installReason != oldState.installReason) {
             return false;
         }
@@ -506,7 +498,6 @@
         hashCode = 31 * hashCode + Boolean.hashCode(virtualPreload);
         hashCode = 31 * hashCode + enabled;
         hashCode = 31 * hashCode + Objects.hashCode(lastDisableAppCaller);
-        hashCode = 31 * hashCode + categoryHint;
         hashCode = 31 * hashCode + installReason;
         hashCode = 31 * hashCode + uninstallReason;
         hashCode = 31 * hashCode + Objects.hashCode(disabledComponents);
@@ -516,6 +507,103 @@
         return hashCode;
     }
 
+    @Override
+    public long getCeDataInode() {
+        return ceDataInode;
+    }
+
+    @NonNull
+    @Override
+    public Set<String> getDisabledComponents() {
+        return disabledComponents;
+    }
+
+    @PackageManager.DistractionRestriction
+    @Override
+    public int getDistractionFlags() {
+        return distractionFlags;
+    }
+
+    @NonNull
+    @Override
+    public Set<String> getEnabledComponents() {
+        return enabledComponents;
+    }
+
+    @Override
+    public int getEnabledState() {
+        return enabled;
+    }
+
+    @Nullable
+    @Override
+    public String getHarmfulAppWarning() {
+        return harmfulAppWarning;
+    }
+
+    @Override
+    public int getInstallReason() {
+        return installReason;
+    }
+
+    @Nullable
+    @Override
+    public String getLastDisableAppCaller() {
+        return lastDisableAppCaller;
+    }
+
+    @Nullable
+    @Override
+    public OverlayPaths getOverlayPaths() {
+        return overlayPaths;
+    }
+
+    @Nullable
+    @Override
+    public Map<String, OverlayPaths> getSharedLibraryOverlayPaths() {
+        return sharedLibraryOverlayPaths;
+    }
+
+    @Override
+    public int getUninstallReason() {
+        return uninstallReason;
+    }
+
+    @Override
+    public boolean isHidden() {
+        return hidden;
+    }
+
+    @Override
+    public boolean isInstalled() {
+        return installed;
+    }
+
+    @Override
+    public boolean isInstantApp() {
+        return instantApp;
+    }
+
+    @Override
+    public boolean isNotLaunched() {
+        return notLaunched;
+    }
+
+    @Override
+    public boolean isStopped() {
+        return stopped;
+    }
+
+    @Override
+    public boolean isSuspended() {
+        return suspended;
+    }
+
+    @Override
+    public boolean isVirtualPreload() {
+        return virtualPreload;
+    }
+
     /**
      * Container to describe suspension parameters.
      */
diff --git a/core/java/android/content/pm/SELinuxUtil.java b/core/java/android/content/pm/SELinuxUtil.java
index 025c0fe..d8d52b7 100644
--- a/core/java/android/content/pm/SELinuxUtil.java
+++ b/core/java/android/content/pm/SELinuxUtil.java
@@ -16,8 +16,6 @@
 
 package android.content.pm;
 
-import com.android.internal.util.ArrayUtils;
-
 /**
  * Utility methods that need to be used in application space.
  * @hide
@@ -31,11 +29,10 @@
     public static final String COMPLETE_STR = ":complete";
 
     /** @hide */
-    public static String assignSeinfoUser(PackageUserState userState) {
+    public static String getSeinfoUser(PackageUserState userState) {
         if (userState.instantApp) {
            return INSTANT_APP_STR + COMPLETE_STR;
         }
         return COMPLETE_STR;
     }
-
 }
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 8bc3734..0a69413 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -19,6 +19,16 @@
       "name": "CarrierAppIntegrationTestCases"
     },
     {
+      "name": "CtsIncrementalInstallHostTestCases",
+      "options": [
+        {
+          "include-filter": "android.incrementalinstall.cts.IncrementalFeatureTest"
+        }
+      ]
+    }
+  ],
+  "presubmit-large": [
+    {
       "name": "CtsContentTestCases",
       "options": [
         {
@@ -31,14 +41,6 @@
           "include-filter": "android.content.pm.cts"
         }
       ]
-    },
-    {
-      "name": "CtsIncrementalInstallHostTestCases",
-      "options": [
-        {
-          "include-filter": "android.incrementalinstall.cts.IncrementalFeatureTest"
-        }
-      ]
     }
   ],
   "postsubmit": [
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 5a89708..76e9fcb 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -343,7 +343,7 @@
     }
 
     public boolean isDemo() {
-        return UserManager.isUserTypeDemo(userType);
+        return UserManager.isUserTypeDemo(userType) || (flags & FLAG_DEMO) != 0;
     }
 
     public boolean isFull() {
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 024c18c..49d4137 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -19,12 +19,15 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Lightweight parsed details about a single APK file.
@@ -44,6 +47,10 @@
     private final @Nullable String mUsesSplitName;
     /** Name of the split APK that this APK is a configuration for */
     private final @Nullable String mConfigForSplit;
+    /** Indicate the types of the required split are necessary for this package to run */
+    private final @Nullable Set<String> mRequiredSplitTypes;
+    /** Split types of this APK */
+    private final @Nullable Set<String> mSplitTypes;
 
     /** Major version number of this package */
     private final int mVersionCodeMajor;
@@ -105,9 +112,9 @@
     /**
      * Indicate the policy to deal with user data when rollback is committed
      *
-     * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RESTORE}
-     * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#WIPE}
-     * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RETAIN}
+     * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE}
+     * @see {@link PackageManager#ROLLBACK_DATA_POLICY_WIPE}
+     * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RETAIN}
      */
     private final int mRollbackDataPolicy;
 
@@ -118,14 +125,17 @@
             boolean debuggable, boolean profileableByShell, boolean multiArch, boolean use32bitAbi,
             boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits,
             String targetPackageName, boolean overlayIsStatic, int overlayPriority,
-            int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy) {
+            int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
+            Set<String> requiredSplitTypes, Set<String> splitTypes) {
         mPath = path;
         mPackageName = packageName;
         mSplitName = splitName;
+        mSplitTypes = splitTypes;
         mFeatureSplit = isFeatureSplit;
         mConfigForSplit = configForSplit;
         mUsesSplitName = usesSplitName;
-        mSplitRequired = isSplitRequired;
+        mRequiredSplitTypes = requiredSplitTypes;
+        mSplitRequired = (isSplitRequired || hasAnyRequiredSplitTypes());
         mVersionCode = versionCode;
         mVersionCodeMajor = versionCodeMajor;
         mRevisionCode = revisionCode;
@@ -156,9 +166,16 @@
         return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
     }
 
+    /**
+     * Return if requiredSplitTypes presents.
+     */
+    private boolean hasAnyRequiredSplitTypes() {
+        return !CollectionUtils.isEmpty(mRequiredSplitTypes);
+    }
 
 
-    // Code below generated by codegen v1.0.22.
+
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -212,6 +229,22 @@
     }
 
     /**
+     * Indicate the types of the required split are necessary for this package to run
+     */
+    @DataClass.Generated.Member
+    public @Nullable Set<String> getRequiredSplitTypes() {
+        return mRequiredSplitTypes;
+    }
+
+    /**
+     * Split types of this APK
+     */
+    @DataClass.Generated.Member
+    public @Nullable Set<String> getSplitTypes() {
+        return mSplitTypes;
+    }
+
+    /**
      * Major version number of this package
      */
     @DataClass.Generated.Member
@@ -388,9 +421,9 @@
     /**
      * Indicate the policy to deal with user data when rollback is committed
      *
-     * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RESTORE}
-     * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#WIPE}
-     * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RETAIN}
+     * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE}
+     * @see {@link PackageManager#ROLLBACK_DATA_POLICY_WIPE}
+     * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RETAIN}
      */
     @DataClass.Generated.Member
     public int getRollbackDataPolicy() {
@@ -398,10 +431,10 @@
     }
 
     @DataClass.Generated(
-            time = 1616985847981L,
-            codegenVersion = "1.0.22",
+            time = 1628562554893L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final  int mRollbackDataPolicy\npublic  long getLongVersionCode()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final  int mRollbackDataPolicy\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index f727a48..d3b6f2b 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -38,6 +38,7 @@
 import android.os.Trace;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.util.Slog;
@@ -58,6 +59,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /** @hide */
 public class ApkLiteParseUtils {
@@ -104,8 +106,11 @@
             final ApkLite baseApk = result.getResult();
             final String packagePath = packageFile.getAbsolutePath();
             return input.success(
-                    new PackageLite(packagePath, baseApk.getPath(), baseApk, null,
-                            null, null, null, null, null, baseApk.getTargetSdkVersion()));
+                    new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */,
+                            null /* isFeatureSplits */, null /* usesSplitNames */,
+                            null /* configForSplit */, null /* splitApkPaths */,
+                            null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
+                            null /* requiredSplitTypes */, null /* splitTypes */));
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -209,6 +214,8 @@
         final int size = ArrayUtils.size(splitApks);
 
         String[] splitNames = null;
+        Set<String>[] requiredSplitTypes = null;
+        Set<String>[] splitTypes = null;
         boolean[] isFeatureSplits = null;
         String[] usesSplitNames = null;
         String[] configForSplits = null;
@@ -216,6 +223,8 @@
         int[] splitRevisionCodes = null;
         if (size > 0) {
             splitNames = new String[size];
+            requiredSplitTypes = new Set[size];
+            splitTypes = new Set[size];
             isFeatureSplits = new boolean[size];
             usesSplitNames = new String[size];
             configForSplits = new String[size];
@@ -227,6 +236,8 @@
 
             for (int i = 0; i < size; i++) {
                 final ApkLite apk = splitApks.get(splitNames[i]);
+                requiredSplitTypes[i] = apk.getRequiredSplitTypes();
+                splitTypes[i] = apk.getSplitTypes();
                 usesSplitNames[i] = apk.getUsesSplitName();
                 isFeatureSplits[i] = apk.isFeatureSplit();
                 configForSplits[i] = apk.getConfigForSplit();
@@ -242,7 +253,7 @@
         return input.success(
                 new PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits,
                         usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes,
-                        baseApk.getTargetSdkVersion()));
+                        baseApk.getTargetSdkVersion(), requiredSplitTypes, splitTypes));
     }
 
     /**
@@ -345,9 +356,15 @@
         if (result.isError()) {
             return input.error(result);
         }
-
         Pair<String, String> packageSplit = result.getResult();
 
+        final ParseResult<Pair<Set<String>, Set<String>>> requiredSplitTypesResult =
+                parseRequiredSplitTypes(input, parser);
+        if (requiredSplitTypesResult.isError()) {
+            return input.error(result);
+        }
+        Pair<Set<String>, Set<String>> requiredSplitTypes = requiredSplitTypesResult.getResult();
+
         int installLocation = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
                 "installLocation", PARSE_DEFAULT_INSTALL_LOCATION);
         int versionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "versionCode", 0);
@@ -522,7 +539,7 @@
                         coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
                         useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
                         overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion,
-                        rollbackDataPolicy));
+                        rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second));
     }
 
     public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
@@ -567,6 +584,54 @@
                 (splitName != null) ? splitName.intern() : splitName));
     }
 
+    /**
+     * Utility method that parses attributes android:requiredSplitTypes and android:splitTypes.
+     */
+    public static ParseResult<Pair<Set<String>, Set<String>>> parseRequiredSplitTypes(
+            ParseInput input, XmlResourceParser parser) {
+        Set<String> requiredSplitTypes = null;
+        Set<String> splitTypes = null;
+        String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "requiredSplitTypes");
+        if (!TextUtils.isEmpty(value)) {
+            final ParseResult<Set<String>> result = separateAndValidateSplitTypes(input, value);
+            if (result.isError()) {
+                return input.error(result);
+            }
+            requiredSplitTypes = result.getResult();
+        }
+
+        value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "splitTypes");
+        if (!TextUtils.isEmpty(value)) {
+            final ParseResult<Set<String>> result = separateAndValidateSplitTypes(input, value);
+            if (result.isError()) {
+                return input.error(result);
+            }
+            splitTypes = result.getResult();
+        }
+
+        return input.success(Pair.create(requiredSplitTypes, splitTypes));
+    }
+
+    private static ParseResult<Set<String>> separateAndValidateSplitTypes(ParseInput input,
+            String values) {
+        final Set<String> ret = new ArraySet<>();
+        for (String value : values.trim().split(",")) {
+            final String type = value.trim();
+            // Using requireFilename as true because it limits length of the name to the
+            // {@link #MAX_FILE_NAME_SIZE}.
+            final ParseResult<?> nameResult = validateName(input, type,
+                    false /* requireSeparator */, true /* requireFilename */);
+            if (nameResult.isError()) {
+                return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Invalid manifest split types: " + nameResult.getErrorMessage());
+            }
+            if (!ret.add(type)) {
+                Slog.w(TAG, type + " was defined multiple times");
+            }
+        }
+        return input.success(ret);
+    }
+
     public static VerifierInfo parseVerifier(AttributeSet attrs) {
         String packageName = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
         String encodedPublicKey = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "publicKey");
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 9fee7bb..747015d 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -213,8 +213,8 @@
         PackageInfo pi = new PackageInfo();
         pi.packageName = pkg.getPackageName();
         pi.splitNames = pkg.getSplitNames();
-        pi.versionCode = pkg.getVersionCode();
-        pi.versionCodeMajor = pkg.getVersionCodeMajor();
+        pi.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
+        pi.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
         pi.baseRevisionCode = pkg.getBaseRevisionCode();
         pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
         pi.versionName = pkg.getVersionName();
@@ -229,7 +229,7 @@
         pi.restrictedAccountType = pkg.getRestrictedAccountType();
         pi.requiredAccountType = pkg.getRequiredAccountType();
         pi.overlayTarget = pkg.getOverlayTarget();
-        pi.targetOverlayableName = pkg.getOverlayTargetName();
+        pi.targetOverlayableName = pkg.getOverlayTargetOverlayableName();
         pi.overlayCategory = pkg.getOverlayCategory();
         pi.overlayPriority = pkg.getOverlayPriority();
         pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
@@ -246,10 +246,10 @@
                 pi.configPreferences = new ConfigurationInfo[size];
                 pkg.getConfigPreferences().toArray(pi.configPreferences);
             }
-            size = pkg.getReqFeatures().size();
+            size = pkg.getRequestedFeatures().size();
             if (size > 0) {
                 pi.reqFeatures = new FeatureInfo[size];
-                pkg.getReqFeatures().toArray(pi.reqFeatures);
+                pkg.getRequestedFeatures().toArray(pi.reqFeatures);
             }
             size = pkg.getFeatureGroups().size();
             if (size > 0) {
@@ -389,10 +389,10 @@
      */
     @NonNull
     public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg,
-            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId,
-            boolean assignUserFields) {
+            @PackageManager.ApplicationInfoFlags int flags, @NonNull PackageUserState state,
+            int userId, boolean assignUserFields) {
         // Make shallow copy so we can store the metadata/libraries safely
-        ApplicationInfo ai = pkg.toAppInfoWithoutState();
+        ApplicationInfo ai = ((ParsingPackageHidden) pkg).toAppInfoWithoutState();
 
         if (assignUserFields) {
             assignUserFields(pkg, ai, userId);
@@ -435,12 +435,9 @@
         }
         ai.enabledSetting = state.enabled;
         if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
-            ai.category = state.categoryHint;
-        }
-        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
         }
-        ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+        ai.seInfoUser = SELinuxUtil.getSeinfoUser(state);
         final OverlayPaths overlayPaths = state.getAllOverlayPaths();
         if (overlayPaths != null) {
             ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]);
@@ -531,11 +528,9 @@
         ai.lockTaskLaunchMode = a.getLockTaskLaunchMode();
         ai.screenOrientation = a.getScreenOrientation();
         ai.resizeMode = a.getResizeMode();
-        Float maxAspectRatio = a.getMaxAspectRatio();
-        ai.setMaxAspectRatio(maxAspectRatio != null ? maxAspectRatio : 0f);
-        Float minAspectRatio = a.getMinAspectRatio();
-        ai.setMinAspectRatio(minAspectRatio != null ? minAspectRatio : 0f);
-        ai.supportsSizeChanges = a.getSupportsSizeChanges();
+        ai.setMaxAspectRatio(a.getMaxAspectRatio());
+        ai.setMinAspectRatio(a.getMinAspectRatio());
+        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/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 9172555..5f5e812 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -22,11 +22,13 @@
 import android.content.pm.VerifierInfo;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Lightweight parsed details about a single package.
@@ -52,6 +54,12 @@
     /** Dependencies of any split APKs, ordered by parsed splitName */
     private final @Nullable String[] mUsesSplitNames;
     private final @Nullable String[] mConfigForSplit;
+    /** Indicate the types of the required split are necessary for base APK to run */
+    private final @Nullable Set<String> mBaseRequiredSplitTypes;
+    /** Indicate the types of the required split are necessary for split APKs to run */
+    private final @Nullable Set<String>[] mRequiredSplitTypes;
+    /** Split type of any split APKs, ordered by parsed splitName */
+    private final @Nullable Set<String>[] mSplitTypes;
     /** Major and minor version number of this package */
     private final int mVersionCodeMajor;
     private final int mVersionCode;
@@ -101,7 +109,7 @@
     public PackageLite(String path, String baseApkPath, ApkLite baseApk,
             String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
             String[] configForSplit, String[] splitApkPaths, int[] splitRevisionCodes,
-            int targetSdk) {
+            int targetSdk, Set<String>[] requiredSplitTypes, Set<String>[] splitTypes) {
         // The following paths may be different from the path in ApkLite because we
         // move or rename the APK files. Use parameters to indicate the correct paths.
         mPath = path;
@@ -119,9 +127,12 @@
         mExtractNativeLibs = baseApk.isExtractNativeLibs();
         mIsolatedSplits = baseApk.isIsolatedSplits();
         mUseEmbeddedDex = baseApk.isUseEmbeddedDex();
-        mSplitRequired = baseApk.isSplitRequired();
+        mBaseRequiredSplitTypes = baseApk.getRequiredSplitTypes();
+        mRequiredSplitTypes = requiredSplitTypes;
+        mSplitRequired = (baseApk.isSplitRequired() || hasAnyRequiredSplitTypes());
         mProfileableByShell = baseApk.isProfileableByShell();
         mSplitNames = splitNames;
+        mSplitTypes = splitTypes;
         mIsFeatureSplits = isFeatureSplits;
         mUsesSplitNames = usesSplitNames;
         mConfigForSplit = configForSplit;
@@ -150,9 +161,19 @@
         return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
     }
 
+    /**
+     * Return if requiredSplitTypes presents in the package.
+     */
+    private boolean hasAnyRequiredSplitTypes() {
+        if (!CollectionUtils.isEmpty(mBaseRequiredSplitTypes)) {
+            return true;
+        }
+        return ArrayUtils.find(mRequiredSplitTypes, r -> !CollectionUtils.isEmpty(r)) != null;
+    }
 
 
-    // Code below generated by codegen v1.0.22.
+
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -221,6 +242,30 @@
     }
 
     /**
+     * Indicate the types of the required split are necessary for base APK to run
+     */
+    @DataClass.Generated.Member
+    public @Nullable Set<String> getBaseRequiredSplitTypes() {
+        return mBaseRequiredSplitTypes;
+    }
+
+    /**
+     * Indicate the types of the required split are necessary for split APKs to run
+     */
+    @DataClass.Generated.Member
+    public @Nullable Set<String>[] getRequiredSplitTypes() {
+        return mRequiredSplitTypes;
+    }
+
+    /**
+     * Split type of any split APKs, ordered by parsed splitName
+     */
+    @DataClass.Generated.Member
+    public @Nullable Set<String>[] getSplitTypes() {
+        return mSplitTypes;
+    }
+
+    /**
      * Major and minor version number of this package
      */
     @DataClass.Generated.Member
@@ -357,10 +402,10 @@
     }
 
     @DataClass.Generated(
-            time = 1615914120261L,
-            codegenVersion = "1.0.22",
+            time = 1628562559343L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 72cc929..14d69cc 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -300,9 +300,7 @@
 
     ParsingPackage setOverlayTarget(String overlayTarget);
 
-    ParsingPackage setOverlayTargetName(String overlayTargetName);
-
-    ParsingPackage setRealPackage(String realPackage);
+    ParsingPackage setOverlayTargetOverlayableName(String overlayTargetOverlayableName);
 
     ParsingPackage setRequiredAccountType(String requiredAccountType);
 
@@ -360,7 +358,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/ParsingPackageHidden.java b/core/java/android/content/pm/parsing/ParsingPackageHidden.java
new file mode 100644
index 0000000..c49d11e
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackageHidden.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+/**
+ * Methods that normal consumers should not have access to. This usually means the field is stateful
+ * or deprecated and should be access through a utility class or a system manager class.
+ * <p>
+ * This is a separate interface, not implemented by the base {@link ParsingPackageRead} because Java
+ * doesn't support non-public interface methods. The class must be cast to this interface.
+ *
+ * @hide
+ */
+interface ParsingPackageHidden {
+
+    /**
+     * @see PackageInfo#versionCode
+     * @see ApplicationInfo#versionCode
+     */
+    int getVersionCode();
+
+    /**
+     * @see PackageInfo#versionCodeMajor
+     */
+    int getVersionCodeMajor();
+
+    // TODO(b/135203078): Hide and enforce going through PackageInfoUtils
+    ApplicationInfo toAppInfoWithoutState();
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 0db6546..5a5f6db 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -89,9 +89,7 @@
  *
  * @hide
  */
-public class ParsingPackageImpl implements ParsingPackage, Parcelable {
-
-    private static final String TAG = "PackageImpl";
+public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden, Parcelable {
 
     public static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
     public static ForInternedString sForInternedString = Parcelling.Cache.getOrCreate(
@@ -147,10 +145,6 @@
     @DataClass.ParcelWith(ForInternedString.class)
     protected String packageName;
 
-    @Nullable
-    @DataClass.ParcelWith(ForInternedString.class)
-    private String realPackage;
-
     @NonNull
     protected String mBaseApkPath;
 
@@ -166,7 +160,7 @@
     private String overlayTarget;
     @Nullable
     @DataClass.ParcelWith(ForInternedString.class)
-    private String overlayTargetName;
+    private String overlayTargetOverlayableName;
     @Nullable
     @DataClass.ParcelWith(ForInternedString.class)
     private String overlayCategory;
@@ -553,7 +547,7 @@
 
             setCompileSdkVersion(manifestArray.getInteger(
                     R.styleable.AndroidManifest_compileSdkVersion, 0));
-            setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
+            setCompileSdkVersionCodeName(manifestArray.getNonConfigurationString(
                     R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
 
             setIsolatedSplitLoading(manifestArray.getBoolean(
@@ -1019,7 +1013,6 @@
         return appInfo;
     }
 
-    @Override
     public ApplicationInfo toAppInfoWithoutStateWithoutFlags() {
         ApplicationInfo appInfo = new ApplicationInfo();
 
@@ -1126,12 +1119,11 @@
         dest.writeInt(this.compileSdkVersion);
         dest.writeString(this.compileSdkVersionCodeName);
         sForInternedString.parcel(this.packageName, dest, flags);
-        dest.writeString(this.realPackage);
         dest.writeString(this.mBaseApkPath);
         dest.writeString(this.restrictedAccountType);
         dest.writeString(this.requiredAccountType);
         sForInternedString.parcel(this.overlayTarget, dest, flags);
-        dest.writeString(this.overlayTargetName);
+        dest.writeString(this.overlayTargetOverlayableName);
         dest.writeString(this.overlayCategory);
         dest.writeInt(this.overlayPriority);
         sForInternedStringValueMap.parcel(this.overlayables, dest, flags);
@@ -1250,12 +1242,11 @@
         this.compileSdkVersion = in.readInt();
         this.compileSdkVersionCodeName = in.readString();
         this.packageName = sForInternedString.unparcel(in);
-        this.realPackage = in.readString();
         this.mBaseApkPath = in.readString();
         this.restrictedAccountType = in.readString();
         this.requiredAccountType = in.readString();
         this.overlayTarget = sForInternedString.unparcel(in);
-        this.overlayTargetName = in.readString();
+        this.overlayTargetOverlayableName = in.readString();
         this.overlayCategory = in.readString();
         this.overlayPriority = in.readInt();
         this.overlayables = sForInternedStringValueMap.unparcel(in);
@@ -1384,6 +1375,11 @@
     }
 
     @Override
+    public long getLongVersionCode() {
+        return mLongVersionCode;
+    }
+
+    @Override
     public int getBaseRevisionCode() {
         return baseRevisionCode;
     }
@@ -1411,12 +1407,6 @@
         return packageName;
     }
 
-    @Nullable
-    @Override
-    public String getRealPackage() {
-        return realPackage;
-    }
-
     @NonNull
     @Override
     public String getBaseApkPath() {
@@ -1448,8 +1438,8 @@
 
     @Nullable
     @Override
-    public String getOverlayTargetName() {
-        return overlayTargetName;
+    public String getOverlayTargetOverlayableName() {
+        return overlayTargetOverlayableName;
     }
 
     @Nullable
@@ -1552,7 +1542,7 @@
 
     @NonNull
     @Override
-    public List<FeatureInfo> getReqFeatures() {
+    public List<FeatureInfo> getRequestedFeatures() {
         return reqFeatures;
     }
 
@@ -1939,13 +1929,13 @@
     }
 
     @Override
-    public int getTargetSandboxVersion() {
-        return targetSandboxVersion;
+    public int getTargetSdkVersion() {
+        return targetSdkVersion;
     }
 
     @Override
-    public int getTargetSdkVersion() {
-        return targetSdkVersion;
+    public int getTargetSandboxVersion() {
+        return targetSandboxVersion;
     }
 
     @Nullable
@@ -2686,8 +2676,8 @@
     }
 
     @Override
-    public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
-        this.compileSdkVersionCodeName = compileSdkVersionCodename;
+    public ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName) {
+        this.compileSdkVersionCodeName = compileSdkVersionCodeName;
         return this;
     }
 
@@ -2698,20 +2688,15 @@
     }
 
     @Override
-    public ParsingPackageImpl setRealPackage(@Nullable String realPackage) {
-        this.realPackage = realPackage;
-        return this;
-    }
-
-    @Override
     public ParsingPackageImpl setRestrictedAccountType(@Nullable String restrictedAccountType) {
         this.restrictedAccountType = restrictedAccountType;
         return this;
     }
 
     @Override
-    public ParsingPackageImpl setOverlayTargetName(@Nullable String overlayTargetName) {
-        this.overlayTargetName = overlayTargetName;
+    public ParsingPackageImpl setOverlayTargetOverlayableName(
+            @Nullable String overlayTargetOverlayableName) {
+        this.overlayTargetOverlayableName = overlayTargetOverlayableName;
         return this;
     }
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageInternal.java b/core/java/android/content/pm/parsing/ParsingPackageInternal.java
new file mode 100644
index 0000000..ca16fa2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackageInternal.java
@@ -0,0 +1,67 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageInfo;
+
+import com.android.internal.R;
+
+/**
+ * Methods which would've been a part of {@link PkgWithoutStatePackageInfo} or {@link
+ * PkgWithoutStateAppInfo}, but are removed/deprecated.
+ * <p>
+ * This is different from {@link ParsingPackageHidden}. The methods in that interface cannot be
+ * accessed by anyone except the parsing utilities, whereas the methods in this interface are valid
+ * and can be accessed by any internal caller that needs it.
+ *
+ * @hide
+ */
+interface ParsingPackageInternal {
+
+    /**
+     * @see PackageInfo#overlayCategory
+     * @see R.styleable#AndroidManifestResourceOverlay_category
+     */
+    @Nullable
+    String getOverlayCategory();
+
+    /**
+     * @see PackageInfo#overlayPriority
+     * @see R.styleable#AndroidManifestResourceOverlay_priority
+     */
+    int getOverlayPriority();
+
+    /**
+     * @see PackageInfo#overlayTarget
+     * @see R.styleable#AndroidManifestResourceOverlay_targetPackage
+     */
+    @Nullable
+    String getOverlayTarget();
+
+    /**
+     * @see PackageInfo#targetOverlayableName
+     * @see R.styleable#AndroidManifestResourceOverlay_targetName
+     */
+    @Nullable
+    String getOverlayTargetOverlayableName();
+
+    /**
+     * @see PackageInfo#mOverlayIsStatic
+     */
+    boolean isOverlayIsStatic();
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index d5bd3a9..4a249bb 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -19,30 +19,18 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureGroupInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.Property;
-import android.content.pm.ServiceInfo;
+import android.content.pm.PackageParser;
 import android.content.pm.SigningDetails;
-import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedAttribution;
-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.os.Bundle;
-import android.os.Parcelable;
 import android.util.ArraySet;
 import android.util.Pair;
-import android.util.SparseArray;
 import android.util.SparseIntArray;
 
 import java.security.PublicKey;
@@ -55,58 +43,35 @@
  *
  * @hide
  */
-@SuppressWarnings("UnusedReturnValue")
-public interface ParsingPackageRead extends Parcelable {
+public interface ParsingPackageRead extends PkgWithoutStateAppInfo, PkgWithoutStatePackageInfo,
+        ParsingPackageInternal {
 
     /**
-     * @see ActivityInfo
-     * @see PackageInfo#activities
-     */
-    @NonNull
-    List<ParsedActivity> getActivities();
-
-    /**
-     * The names of packages to adopt ownership of permissions from, parsed under
-     * {@link ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
+     * The names of packages to adopt ownership of permissions from, parsed under {@link
+     * PackageParser#TAG_ADOPT_PERMISSIONS}.
+     *
      * @see R.styleable#AndroidManifestOriginalPackage_name
      */
     @NonNull
     List<String> getAdoptPermissions();
 
-    /**
-     * @see PackageInfo#configPreferences
-     * @see R.styleable#AndroidManifestUsesConfiguration
-     */
-    @NonNull
-    List<ConfigurationInfo> getConfigPreferences();
-
     @NonNull
     List<ParsedAttribution> getAttributions();
 
     /**
-     * @see PackageInfo#featureGroups
-     * @see R.styleable#AndroidManifestUsesFeature
-     */
-    @NonNull
-    List<FeatureGroupInfo> getFeatureGroups();
-
-    /**
      * Permissions requested but not in the manifest. These may have been split or migrated from
      * previous versions/definitions.
      */
     @NonNull
     List<String> getImplicitPermissions();
 
-    /**
-     * @see android.content.pm.InstrumentationInfo
-     * @see PackageInfo#instrumentation
-     */
     @NonNull
-    List<ParsedInstrumentation> getInstrumentations();
+    List<ParsedUsesPermission> getUsesPermissions();
 
     /**
-     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
-     * {@link ParsingPackageUtils#TAG_KEY_SETS}.
+     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
+     * PackageParser#TAG_KEY_SETS}.
+     *
      * @see R.styleable#AndroidManifestKeySet
      * @see R.styleable#AndroidManifestPublicKey
      */
@@ -115,14 +80,31 @@
 
     /**
      * Library names this package is declared as, for use by other packages with "uses-library".
+     *
      * @see R.styleable#AndroidManifestLibrary
      */
     @NonNull
     List<String> getLibraryNames();
 
     /**
-     * For system use to migrate from an old package name to a new one, moving over data
-     * if available.
+     * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?)
+     */
+    @Nullable
+    Bundle getMetaData();
+
+    @Nullable
+    Set<String> getMimeGroups();
+
+    /**
+     * @see R.styleable#AndroidManifestExtensionSdk
+     */
+    @Nullable
+    SparseIntArray getMinExtensionVersions();
+
+    /**
+     * For system use to migrate from an old package name to a new one, moving over data if
+     * available.
+     *
      * @see R.styleable#AndroidManifestOriginalPackage}
      */
     @NonNull
@@ -135,13 +117,6 @@
     Map<String, String> getOverlayables();
 
     /**
-     * @see android.content.pm.PermissionInfo
-     * @see PackageInfo#permissions
-     */
-    @NonNull
-    List<ParsedPermission> getPermissions();
-
-    /**
      * @see android.content.pm.PermissionGroupInfo
      */
     @NonNull
@@ -149,131 +124,30 @@
 
     /**
      * Used to determine the default preferred handler of an {@link Intent}.
-     *
-     * Map of component className to intent info inside that component.
-     * TODO(b/135203078): Is this actually used/working?
+     * <p>
+     * Map of component className to intent info inside that component. TODO(b/135203078): Is this
+     * actually used/working?
      */
     @NonNull
     List<Pair<String, ParsedIntentInfo>> getPreferredActivityFilters();
 
     /**
-     * System protected broadcasts.
-     * @see R.styleable#AndroidManifestProtectedBroadcast
-     */
-    @NonNull
-    List<String> getProtectedBroadcasts();
-
-    /**
-     * @see android.content.pm.ProviderInfo
-     * @see PackageInfo#providers
-     */
-    @NonNull
-    List<ParsedProvider> getProviders();
-
-    /**
      * @see android.content.pm.ProcessInfo
      */
     @NonNull
     Map<String, ParsedProcess> getProcesses();
 
     /**
-     * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even
-     * though they represent different functionality.
-     * TODO(b/135203078): Reconsider this and maybe make ParsedReceiver so it's not so confusing
-     * @see ActivityInfo
-     * @see PackageInfo#receivers
+     * System protected broadcasts.
+     *
+     * @see R.styleable#AndroidManifestProtectedBroadcast
      */
     @NonNull
-    List<ParsedActivity> getReceivers();
-
-    /**
-     * @see PackageInfo#reqFeatures
-     * @see R.styleable#AndroidManifestUsesFeature
-     */
-    @NonNull
-    List<FeatureInfo> getReqFeatures();
-
-    /**
-     * @deprecated consider migrating to {@link #getUsesPermissions} which has
-     *             more parsed details, such as flags
-     */
-    @NonNull
-    @Deprecated
-    List<String> getRequestedPermissions();
-
-    /**
-     * All the permissions declared. This is an effective set, and may include permissions
-     * transformed from split/migrated permissions from previous versions, so may not be exactly
-     * what the package declares in its manifest.
-     * @see PackageInfo#requestedPermissions
-     * @see R.styleable#AndroidManifestUsesPermission
-     */
-    @NonNull
-    List<ParsedUsesPermission> getUsesPermissions();
-
-    /**
-     * Returns the properties set on the application
-     */
-    @NonNull
-    Map<String, Property> getProperties();
-
-    /**
-     * Whether or not the app requested explicitly resizeable Activities.
-     * A null value means nothing was explicitly requested.
-     */
-    @Nullable
-    Boolean getResizeableActivity();
-
-    /**
-     * @see ServiceInfo
-     * @see PackageInfo#services
-     */
-    @NonNull
-    List<ParsedService> getServices();
-
-    /** @see R.styleable#AndroidManifestUsesLibrary */
-    @NonNull
-    List<String> getUsesLibraries();
-
-    /**
-     * Like {@link #getUsesLibraries()}, but marked optional by setting
-     * {@link R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected
-     * to handle absence manually.
-     * @see R.styleable#AndroidManifestUsesLibrary
-     */
-    @NonNull
-    List<String> getUsesOptionalLibraries();
-
-    /** @see R.styleabele#AndroidManifestUsesNativeLibrary */
-    @NonNull
-    List<String> getUsesNativeLibraries();
-
-    /**
-     * Like {@link #getUsesNativeLibraries()}, but marked optional by setting
-     * {@link R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is
-     * expected to handle absence manually.
-     * @see R.styleable#AndroidManifestUsesNativeLibrary
-     */
-    @NonNull
-    List<String> getUsesOptionalNativeLibraries();
-
-    /**
-     * TODO(b/135203078): Move static library stuff to an inner data class
-     * @see R.styleable#AndroidManifestUsesStaticLibrary
-     */
-    @NonNull
-    List<String> getUsesStaticLibraries();
-
-    /** @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest */
-    @Nullable
-    String[][] getUsesStaticLibrariesCertDigests();
-
-    /** @see R.styleable#AndroidManifestUsesStaticLibrary_version */
-    @Nullable
-    long[] getUsesStaticLibrariesVersions();
+    List<String> getProtectedBroadcasts();
 
     /**
      * Intents that this package may query or require and thus requires visibility into.
+     *
      * @see R.styleable#AndroidManifestQueriesIntent
      */
     @NonNull
@@ -281,6 +155,7 @@
 
     /**
      * Other packages that this package may query or require and thus requires visibility into.
+     *
      * @see R.styleable#AndroidManifestQueriesPackage
      */
     @NonNull
@@ -288,643 +163,138 @@
 
     /**
      * Authorities that this package may query or require and thus requires visibility into.
+     *
      * @see R.styleable#AndroidManifestQueriesProvider
      */
     @NonNull
     Set<String> getQueriesProviders();
 
     /**
-     * We store the application meta-data independently to avoid multiple unwanted references
-     * TODO(b/135203078): What does this comment mean?
-     * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?)
-     */
-    @Nullable
-    Bundle getMetaData();
-
-    /** @see R.styleable#AndroidManifestApplication_forceQueryable */
-    boolean isForceQueryable();
-
-    /**
-     * @see ApplicationInfo#maxAspectRatio
-     * @see R.styleable#AndroidManifestApplication_maxAspectRatio
-     */
-    float getMaxAspectRatio();
-
-    /**
-     * @see ApplicationInfo#minAspectRatio
-     * @see R.styleable#AndroidManifestApplication_minAspectRatio
-     */
-    float getMinAspectRatio();
-
-    /**
-     * @see ApplicationInfo#permission
-     * @see R.styleable#AndroidManifestApplication_permission
-     */
-    @Nullable
-    String getPermission();
-
-    /**
-     * @see ApplicationInfo#processName
-     * @see R.styleable#AndroidManifestApplication_process
-     */
-    @NonNull
-    String getProcessName();
-
-    /**
-     * @see PackageInfo#sharedUserId
-     * @see R.styleable#AndroidManifest_sharedUserId
-     */
-    @Deprecated
-    @Nullable
-    String getSharedUserId();
-
-    /** @see R.styleable#AndroidManifestStaticLibrary_name */
-    @Nullable
-    String getStaticSharedLibName();
-
-    /**
-     * @see ApplicationInfo#taskAffinity
-     * @see R.styleable#AndroidManifestApplication_taskAffinity
-     */
-    @Nullable
-    String getTaskAffinity();
-
-    /**
-     * @see ApplicationInfo#targetSdkVersion
-     * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion
-     */
-    int getTargetSdkVersion();
-
-    /**
-     * @see ApplicationInfo#uiOptions
-     * @see R.styleable#AndroidManifestApplication_uiOptions
-     */
-    int getUiOptions();
-
-    boolean isCrossProfile();
-
-    boolean isResizeableActivityViaSdkVersion();
-
-    /** @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED */
-    boolean isBaseHardwareAccelerated();
-
-    /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_resizeable
-     * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS
-     */
-    boolean isResizeable();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE */
-    boolean isAllowAudioPlaybackCapture();
-
-    /** @see ApplicationInfo#FLAG_ALLOW_BACKUP */
-    boolean isAllowBackup();
-
-    /** @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA */
-    boolean isAllowClearUserData();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE */
-    boolean isAllowClearUserDataOnFailedRestore();
-
-    /** @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING */
-    boolean isAllowTaskReparenting();
-
-    /**
-     * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY
-     * @see ApplicationInfo#isResourceOverlay()
-     */
-    boolean isOverlay();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND */
-    boolean isBackupInForeground();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE */
-    boolean isCantSaveState();
-
-    /** @see ApplicationInfo#FLAG_DEBUGGABLE */
-    boolean isDebuggable();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE */
-    boolean isDefaultToDeviceProtectedStorage();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE */
-    boolean isDirectBootAware();
-
-    /** @see ApplicationInfo#FLAG_EXTERNAL_STORAGE */
-    boolean isExternalStorage();
-
-    /** @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS */
-    boolean isExtractNativeLibs();
-
-    /** @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY */
-    boolean isFullBackupOnly();
-
-    /** @see ApplicationInfo#FLAG_HAS_CODE */
-    boolean isHasCode();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA */
-    boolean isHasFragileUserData();
-
-    /** @see ApplicationInfo#FLAG_IS_GAME */
-    @Deprecated
-    boolean isGame();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING */
-    boolean isIsolatedSplitLoading();
-
-    /** @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE */
-    boolean isKillAfterRestore();
-
-    /** @see ApplicationInfo#FLAG_LARGE_HEAP */
-    boolean isLargeHeap();
-
-    /** @see ApplicationInfo#FLAG_MULTIARCH */
-    boolean isMultiArch();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE */
-    boolean isPartiallyDirectBootAware();
-
-    /** @see ApplicationInfo#FLAG_PERSISTENT */
-    boolean isPersistent();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL */
-    boolean isProfileableByShell();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_EXT_PROFILEABLE */
-    boolean isProfileable();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE */
-    boolean isRequestLegacyExternalStorage();
-
-    /** @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION */
-    boolean isRestoreAnyVersion();
-
-    // ParsingPackageRead setSplitHasCode(int splitIndex, boolean splitHasCode);
-
-    /** Flags of any split APKs; ordered by parsed splitName */
-    @Nullable
-    int[] getSplitFlags();
-
-    /** @see ApplicationInfo#splitSourceDirs */
-    @Nullable
-    String[] getSplitCodePaths();
-
-    /** @see ApplicationInfo#splitDependencies */
-    @Nullable
-    SparseArray<int[]> getSplitDependencies();
-
-    /**
-     * @see ApplicationInfo#splitNames
-     * @see PackageInfo#splitNames
-     */
-    @Nullable
-    String[] getSplitNames();
-
-    /** @see PackageInfo#splitRevisionCodes */
-    int[] getSplitRevisionCodes();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY */
-    boolean isStaticSharedLibrary();
-
-    /** @see ApplicationInfo#FLAG_SUPPORTS_RTL */
-    boolean isSupportsRtl();
-
-    /** @see ApplicationInfo#FLAG_TEST_ONLY */
-    boolean isTestOnly();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX */
-    boolean isUseEmbeddedDex();
-
-    /** @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC */
-    boolean isUsesCleartextTraffic();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API */
-    boolean isUsesNonSdkApi();
-
-    /**
-     * Set if the any of components are visible to instant applications.
-     * @see R.styleable#AndroidManifestActivity_visibleToInstantApps
-     * @see R.styleable#AndroidManifestProvider_visibleToInstantApps
-     * @see R.styleable#AndroidManifestService_visibleToInstantApps
-     */
-    boolean isVisibleToInstantApps();
-
-    /** @see ApplicationInfo#FLAG_VM_SAFE_MODE */
-    boolean isVmSafeMode();
-
-    /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_anyDensity
-     * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES
-     */
-    boolean isAnyDensity();
-
-    /**
-     * @see ApplicationInfo#appComponentFactory
-     * @see R.styleable#AndroidManifestApplication_appComponentFactory
-     */
-    @Nullable
-    String getAppComponentFactory();
-
-    /**
-     * @see ApplicationInfo#backupAgentName
-     * @see R.styleable#AndroidManifestApplication_backupAgent
-     */
-    @Nullable
-    String getBackupAgentName();
-
-    /**
-     * @see ApplicationInfo#banner
-     * @see R.styleable#AndroidManifestApplication_banner
-     */
-    int getBanner();
-
-    /**
-     * @see ApplicationInfo#category
-     * @see R.styleable#AndroidManifestApplication_appCategory
-     */
-    int getCategory();
-
-    /**
-     * @see ApplicationInfo#classLoaderName
-     * @see R.styleable#AndroidManifestApplication_classLoader
-     */
-    @Nullable
-    String getClassLoaderName();
-
-    /**
-     * @see ApplicationInfo#className
-     * @see R.styleable#AndroidManifestApplication_name
-     */
-    @Nullable
-    String getClassName();
-
-    String getPackageName();
-
-    /** Path of base APK */
-    String getBaseApkPath();
-
-    /**
-     * Path where this package was found on disk. For monolithic packages
-     * this is path to single base APK file; for cluster packages this is
-     * path to the cluster directory.
-     */
-    @NonNull
-    String getPath();
-
-    /**
-     * @see ApplicationInfo#compatibleWidthLimitDp
-     * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp
-     */
-    int getCompatibleWidthLimitDp();
-
-    /**
-     * @see ApplicationInfo#descriptionRes
-     * @see R.styleable#AndroidManifestApplication_description
-     */
-    int getDescriptionRes();
-
-    /**
-     * @see ApplicationInfo#enabled
-     * @see R.styleable#AndroidManifestApplication_enabled
-     */
-    boolean isEnabled();
-
-    /**
-     * @see ApplicationInfo#fullBackupContent
-     * @see R.styleable#AndroidManifestApplication_fullBackupContent
-     */
-    int getFullBackupContent();
-
-    /**
-     * @see R.styleable#AndroidManifestApplication_dataExtractionRules
-     */
-    int getDataExtractionRules();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */
-    boolean isHasDomainUrls();
-
-    /**
-     * @see ApplicationInfo#iconRes
-     * @see R.styleable#AndroidManifestApplication_icon
-     */
-    int getIconRes();
-
-    /**
-     * @see ApplicationInfo#installLocation
-     * @see R.styleable#AndroidManifest_installLocation
-     */
-    int getInstallLocation();
-
-    /**
-     * @see ApplicationInfo#labelRes
-     * @see R.styleable#AndroidManifestApplication_label
-     */
-    int getLabelRes();
-
-    /**
-     * @see ApplicationInfo#largestWidthLimitDp
-     * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
-     */
-    int getLargestWidthLimitDp();
-
-    /**
-     * @see ApplicationInfo#logo
-     * @see R.styleable#AndroidManifestApplication_logo
-     */
-    int getLogo();
-
-    /**
-     * @see ApplicationInfo#manageSpaceActivityName
-     * @see R.styleable#AndroidManifestApplication_manageSpaceActivity
-     */
-    @Nullable
-    String getManageSpaceActivityName();
-
-    /**
-     * @see ApplicationInfo#minExtensionVersions
-     * @see R.styleable#AndroidManifestExtensionSdk
-     */
-    @Nullable
-    SparseIntArray getMinExtensionVersions();
-
-    /**
-     * @see ApplicationInfo#minSdkVersion
-     * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion
-     */
-    int getMinSdkVersion();
-
-    /**
-     * @see ApplicationInfo#networkSecurityConfigRes
-     * @see R.styleable#AndroidManifestApplication_networkSecurityConfig
-     */
-    int getNetworkSecurityConfigRes();
-
-    /**
-     * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
-     * Otherwise, it's stored as {@link #getLabelRes()}.
-     * @see ApplicationInfo#nonLocalizedLabel
-     * @see R.styleable#AndroidManifestApplication_label
-     */
-    @Nullable
-    CharSequence getNonLocalizedLabel();
-
-    /**
-     * @see PackageInfo#overlayCategory
-     * @see R.styleable#AndroidManifestResourceOverlay_category
-     */
-    @Nullable
-    String getOverlayCategory();
-
-    /** @see PackageInfo#mOverlayIsStatic */
-    boolean isOverlayIsStatic();
-
-    /**
-     * @see PackageInfo#overlayPriority
-     * @see R.styleable#AndroidManifestResourceOverlay_priority
-     */
-    int getOverlayPriority();
-
-    /**
-     * @see PackageInfo#overlayTarget
-     * @see R.styleable#AndroidManifestResourceOverlay_targetPackage
-     */
-    @Nullable
-    String getOverlayTarget();
-
-    /**
-     * @see PackageInfo#targetOverlayableName
-     * @see R.styleable#AndroidManifestResourceOverlay_targetName
-     */
-    @Nullable
-    String getOverlayTargetName();
-
-    /**
-     * If a system app declares {@link #getOriginalPackages()}, and the app was previously installed
-     * under one of those original package names, the {@link #getPackageName()} system identifier
-     * will be changed to that previously installed name. This will then be non-null, set to the
-     * manifest package name, for tracking the package under its true name.
-     *
-     * TODO(b/135203078): Remove this in favor of checking originalPackages.isEmpty and
-     *  getManifestPackageName
-     */
-    @Nullable
-    String getRealPackage();
-
-    /**
-     * The required account type without which this application will not function.
-     *
-     * @see PackageInfo#requiredAccountType
-     * @see R.styleable#AndroidManifestApplication_requiredAccountType
-     */
-    @Nullable
-    String getRequiredAccountType();
-
-    /**
-     * @see PackageInfo#requiredForAllUsers
-     * @see R.styleable#AndroidManifestApplication_requiredForAllUsers
-     */
-    boolean isRequiredForAllUsers();
-
-    /**
-     * @see ApplicationInfo#requiresSmallestWidthDp
-     * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
-     */
-    int getRequiresSmallestWidthDp();
-
-    /**
      * SHA-512 hash of the only APK that can be used to update a system package.
+     *
      * @see R.styleable#AndroidManifestRestrictUpdate
      */
     @Nullable
     byte[] getRestrictUpdateHash();
 
     /**
-     * The restricted account authenticator type that is used by this application
-     *
-     * @see PackageInfo#restrictedAccountType
-     * @see R.styleable#AndroidManifestApplication_restrictedAccountType
-     */
-    @Nullable
-    String getRestrictedAccountType();
-
-    /**
-     * @see ApplicationInfo#roundIconRes
-     * @see R.styleable#AndroidManifestApplication_roundIcon
-     */
-    int getRoundIconRes();
-
-    /**
-     * @see PackageInfo#sharedUserLabel
-     * @see R.styleable#AndroidManifest_sharedUserLabel
-     */
-    @Deprecated
-    int getSharedUserLabel();
-
-    /**
      * The signature data of all APKs in this package, which must be exactly the same across the
      * base and splits.
      */
     SigningDetails getSigningDetails();
 
     /**
-     * @see ApplicationInfo#splitClassLoaderNames
-     * @see R.styleable#AndroidManifestApplication_classLoader
+     * Returns the properties set on the application
+     */
+    @NonNull
+    Map<String, Property> getProperties();
+
+    /**
+     * Flags of any split APKs; ordered by parsed splitName
      */
     @Nullable
-    String[] getSplitClassLoaderNames();
+    int[] getSplitFlags();
 
-    /** @see R.styleable#AndroidManifestStaticLibrary_version */
+    /**
+     * @see R.styleable#AndroidManifestStaticLibrary_name
+     */
+    @Nullable
+    String getStaticSharedLibName();
+
+    /**
+     * @see R.styleable#AndroidManifestStaticLibrary_version
+     */
     long getStaticSharedLibVersion();
 
     /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_largeScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
-     */
-    boolean isSupportsLargeScreens();
-
-    /**
-     * If omitted from manifest, returns true.
-     * @see R.styleable#AndroidManifestSupportsScreens_normalScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
-     */
-    boolean isSupportsNormalScreens();
-
-    /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_smallScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
-     */
-    boolean isSupportsSmallScreens();
-
-    /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#GINGERBREAD}.
-     * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
-     */
-    boolean isSupportsExtraLargeScreens();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING */
-    boolean isAllowNativeHeapPointerTagging();
-
-    int getAutoRevokePermissions();
-
-    boolean hasPreserveLegacyExternalStorage();
-
-    /**
-     * @see ApplicationInfo#targetSandboxVersion
-     * @see R.styleable#AndroidManifest_targetSandboxVersion
-     */
-    @Deprecated
-    int getTargetSandboxVersion();
-
-    /**
-     * @see ApplicationInfo#theme
-     * @see R.styleable#AndroidManifestApplication_theme
-     */
-    int getTheme();
-
-    /**
-     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
-     * {@link ParsingPackageUtils#TAG_KEY_SETS}.
+     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
+     * PackageParser#TAG_KEY_SETS}.
+     *
      * @see R.styleable#AndroidManifestUpgradeKeySet
      */
     @NonNull
     Set<String> getUpgradeKeySets();
 
     /**
-     * The install time abi override to choose 32bit abi's when multiple abi's
-     * are present. This is only meaningfull for multiarch applications.
-     * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
+     * @see R.styleable#AndroidManifestUsesLibrary
+     */
+    @NonNull
+    List<String> getUsesLibraries();
+
+    /**
+     * @see R.styleable#AndroidManifestUsesNativeLibrary
+     */
+    @NonNull
+    List<String> getUsesNativeLibraries();
+
+    /**
+     * Like {@link #getUsesLibraries()}, but marked optional by setting {@link
+     * R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected to handle
+     * absence manually.
+     *
+     * @see R.styleable#AndroidManifestUsesLibrary
+     */
+    @NonNull
+    List<String> getUsesOptionalLibraries();
+
+    /**
+     * Like {@link #getUsesNativeLibraries()}, but marked optional by setting {@link
+     * R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is expected to
+     * handle absence manually.
+     *
+     * @see R.styleable#AndroidManifestUsesNativeLibrary
+     */
+    @NonNull
+    List<String> getUsesOptionalNativeLibraries();
+
+    /**
+     * TODO(b/135203078): Move static library stuff to an inner data class
+     *
+     * @see R.styleable#AndroidManifestUsesStaticLibrary
+     */
+    @NonNull
+    List<String> getUsesStaticLibraries();
+
+    /**
+     * @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest
+     */
+    @Nullable
+    String[][] getUsesStaticLibrariesCertDigests();
+
+    /**
+     * @see R.styleable#AndroidManifestUsesStaticLibrary_version
+     */
+    @Nullable
+    long[] getUsesStaticLibrariesVersions();
+
+    boolean hasPreserveLegacyExternalStorage();
+
+    /**
+     * @see R.styleable#AndroidManifestApplication_forceQueryable
+     */
+    boolean isForceQueryable();
+
+    /**
+     * @see ApplicationInfo#FLAG_IS_GAME
+     */
+    @Deprecated
+    boolean isGame();
+
+    /**
+     * The install time abi override to choose 32bit abi's when multiple abi's are present. This is
+     * only meaningful for multiarch applications. The use32bitAbi attribute is ignored if
+     * cpuAbiOverride is also set.
+     *
+     * @see R.attr#use32bitAbi
      */
     boolean isUse32BitAbi();
 
-    /** @see ApplicationInfo#volumeUuid */
-    @Nullable
-    String getVolumeUuid();
-
-    /** @see ApplicationInfo#zygotePreloadName */
-    @Nullable
-    String getZygotePreloadName();
-
-    /** Revision code of base APK */
-    int getBaseRevisionCode();
-
-    /** @see PackageInfo#versionName */
-    @Nullable
-    String getVersionName();
-
-    /** @see PackageInfo#versionCodeMajor */
-    @Nullable
-    int getVersionCode();
-
-    /** @see PackageInfo#versionCodeMajor */
-    @Nullable
-    int getVersionCodeMajor();
-
     /**
-     * @see ApplicationInfo#compileSdkVersion
-     * @see R.styleable#AndroidManifest_compileSdkVersion
+     * Set if the any of components are visible to instant applications.
+     *
+     * @see R.styleable#AndroidManifestActivity_visibleToInstantApps
+     * @see R.styleable#AndroidManifestProvider_visibleToInstantApps
+     * @see R.styleable#AndroidManifestService_visibleToInstantApps
      */
-    int getCompileSdkVersion();
-
-    /**
-     * @see ApplicationInfo#compileSdkVersionCodename
-     * @see R.styleable#AndroidManifest_compileSdkVersionCodename
-     */
-    @Nullable
-    String getCompileSdkVersionCodeName();
-
-    @Nullable
-    Set<String> getMimeGroups();
-
-    /**
-     * @see ApplicationInfo#gwpAsanMode
-     * @see R.styleable#AndroidManifest_gwpAsanMode
-     */
-    @ApplicationInfo.GwpAsanMode
-    int getGwpAsanMode();
-
-    /**
-     * @see ApplicationInfo#memtagMode
-     * @see R.styleable#AndroidManifest_memtagMode
-     */
-    @ApplicationInfo.MemtagMode
-    int getMemtagMode();
-
-    /**
-     * @see ApplicationInfo#nativeHeapZeroInitialized
-     * @see R.styleable#AndroidManifest_nativeHeapZeroInitialized
-     */
-    @ApplicationInfo.NativeHeapZeroInitialized
-    int getNativeHeapZeroInitialized();
-    @Nullable
-    Boolean hasRequestRawExternalStorageAccess();
-
-    /**
-     * @see ApplicationInfo#hasRequestForegroundServiceExemption()
-     * @see R.styleable#AndroidManifest_requestForegroundServiceExemption
-     */
-    boolean hasRequestForegroundServiceExemption();
-
-    // TODO(b/135203078): Hide and enforce going through PackageInfoUtils
-    ApplicationInfo toAppInfoWithoutState();
-
-    /**
-     * same as toAppInfoWithoutState except without flag computation.
-     */
-    ApplicationInfo toAppInfoWithoutStateWithoutFlags();
-
-    /**
-     * Whether or not the app has said its attribution tags can be made user-visible.
-     * @see ApplicationInfo#areAttributionsUserVisible()
-     */
-    boolean areAttributionsUserVisible();
+    boolean isVisibleToInstantApps();
 }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 809a544..69cf32f 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -150,6 +150,7 @@
     public static final boolean DEBUG_JAR = false;
     public static final boolean DEBUG_BACKUP = false;
     public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
+    public static final float ASPECT_RATIO_NOT_SET = -1f;
 
     /** File name in an APK for the Android manifest. */
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
@@ -234,7 +235,7 @@
      * For those names would be used as a part of the file name. Limits size to 223 and reserves 32
      * for the OS.
      */
-    private static final int MAX_FILE_NAME_SIZE = 223;
+    static final int MAX_FILE_NAME_SIZE = 223;
 
     /**
      * @see #parseDefault(ParseInput, File, int, List, boolean)
@@ -996,6 +997,11 @@
 
     private static ParseResult<ParsingPackage> parseSharedUser(ParseInput input,
             ParsingPackage pkg, TypedArray sa) {
+        int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
+        if ((maxSdkVersion != 0) && maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT) {
+            return input.success(pkg);
+        }
+
         String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa);
         if (TextUtils.isEmpty(str)) {
             return input.success(pkg);
@@ -2091,7 +2097,7 @@
             pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1));
             pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1));
             if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) {
-                Boolean v = sa.getBoolean(
+                final boolean v = sa.getBoolean(
                         R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false);
                 pkg.setNativeHeapZeroInitialized(
                         v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
@@ -2672,7 +2678,7 @@
         for (int index = 0; index < activitiesSize; index++) {
             ParsedActivity activity = activities.get(index);
             // If the max aspect ratio for the activity has already been set, skip.
-            if (activity.getMaxAspectRatio() != null) {
+            if (activity.getMaxAspectRatio() != ASPECT_RATIO_NOT_SET) {
                 continue;
             }
 
@@ -2701,7 +2707,7 @@
         int activitiesSize = activities.size();
         for (int index = 0; index < activitiesSize; index++) {
             ParsedActivity activity = activities.get(index);
-            if (activity.getMinAspectRatio() == null) {
+            if (activity.getMinAspectRatio() == ASPECT_RATIO_NOT_SET) {
                 activity.setMinAspectRatio(activity.getResizeMode(), minAspectRatio);
             }
         }
@@ -2754,7 +2760,7 @@
             return input.success(pkg.setOverlay(true)
                     .setOverlayTarget(target)
                     .setOverlayPriority(priority)
-                    .setOverlayTargetName(
+                    .setOverlayTargetOverlayableName(
                             sa.getString(R.styleable.AndroidManifestResourceOverlay_targetName))
                     .setOverlayCategory(
                             sa.getString(R.styleable.AndroidManifestResourceOverlay_category))
@@ -2834,9 +2840,6 @@
                     R.styleable.AndroidManifestOriginalPackage_name,
                     0);
             if (!pkg.getPackageName().equals(orig)) {
-                if (pkg.getOriginalPackages().isEmpty()) {
-                    pkg.setRealPackage(pkg.getPackageName());
-                }
                 pkg.addOriginalPackage(orig);
             }
             return input.success(pkg);
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
index 289716a..f3a1740 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -41,6 +41,8 @@
     public static final int DEFAULT_MIN_SDK_VERSION = 1;
     public static final int DEFAULT_TARGET_SDK_VERSION = 0;
 
+    public static final int NOT_SET = -1;
+
     @Nullable
     public static String buildClassName(String pkg, CharSequence clsSeq) {
         if (clsSeq == null || clsSeq.length() <= 0) {
diff --git a/core/java/android/content/pm/parsing/PkgWithoutStateAppInfo.java b/core/java/android/content/pm/parsing/PkgWithoutStateAppInfo.java
new file mode 100644
index 0000000..fcad10c
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PkgWithoutStateAppInfo.java
@@ -0,0 +1,642 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+
+/**
+ * Container for fields that are eventually exposed through {@link ApplicationInfo}.
+ * <p>
+ * The following are dependent on system state and explicitly removed from this interface. They must
+ * be accessed by other means:
+ * <ul>
+ *    <li>{@link ApplicationInfo#credentialProtectedDataDir}</li>
+ *    <li>{@link ApplicationInfo#dataDir}</li>
+ *    <li>{@link ApplicationInfo#deviceProtectedDataDir}</li>
+ *    <li>{@link ApplicationInfo#enabledSetting}</li>
+ *    <li>{@link ApplicationInfo#enabled}</li>
+ *    <li>{@link ApplicationInfo#FLAG_INSTALLED}</li>
+ *    <li>{@link ApplicationInfo#FLAG_STOPPED}</li>
+ *    <li>{@link ApplicationInfo#FLAG_SUSPENDED}</li>
+ *    <li>{@link ApplicationInfo#FLAG_UPDATED_SYSTEM_APP}</li>
+ *    <li>{@link ApplicationInfo#hiddenUntilInstalled}</li>
+ *    <li>{@link ApplicationInfo#primaryCpuAbi}</li>
+ *    <li>{@link ApplicationInfo#PRIVATE_FLAG_HIDDEN}</li>
+ *    <li>{@link ApplicationInfo#PRIVATE_FLAG_INSTANT}</li>
+ *    <li>{@link ApplicationInfo#PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER}</li>
+ *    <li>{@link ApplicationInfo#PRIVATE_FLAG_VIRTUAL_PRELOAD}</li>
+ *    <li>{@link ApplicationInfo#resourceDirs}</li>
+ *    <li>{@link ApplicationInfo#secondaryCpuAbi}</li>
+ *    <li>{@link ApplicationInfo#seInfoUser}</li>
+ *    <li>{@link ApplicationInfo#seInfo}</li>
+ *    <li>{@link ApplicationInfo#sharedLibraryFiles}</li>
+ *    <li>{@link ApplicationInfo#sharedLibraryInfos}</li>
+ *    <li>{@link ApplicationInfo#uid}</li>
+ * </ul>
+ * The following are derived from other fields and thus not provided specifically:
+ * <ul>
+ *    <li>{@link ApplicationInfo#getBaseResourcePath}</li>
+ *    <li>{@link ApplicationInfo#getResourcePath}</li>
+ *    <li>{@link ApplicationInfo#getSplitResourcePaths}</li>
+ *    <li>{@link ApplicationInfo#publicSourceDir}</li>
+ *    <li>{@link ApplicationInfo#scanPublicSourceDir}</li>
+ *    <li>{@link ApplicationInfo#splitPublicSourceDirs}</li>
+ *    <li>{@link ApplicationInfo#storageUuid}</li>
+ * </ul>
+ * The following were deprecated at migration time and thus removed from this interface:
+ * <ul>
+ *    <li>{@link ApplicationInfo#FLAG_IS_GAME}</li>
+ *    <li>{@link ApplicationInfo#targetSandboxVersion}</li>
+ *    <li>{@link ApplicationInfo#versionCode}</li>
+ * </ul>
+ * TODO: The following fields are just not available at all. Never filled, even by legacy parsing?
+ * <ul>
+ *    <li>{@link ApplicationInfo#FLAG_IS_DATA_ONLY}</li>
+ * </ul>
+ *
+ * @hide
+ */
+public interface PkgWithoutStateAppInfo {
+
+    /**
+     * @see ApplicationInfo#areAttributionsUserVisible()
+     * @see R.styleable#AndroidManifestApplication_attributionsAreUserVisible
+     */
+    @Nullable
+    boolean areAttributionsUserVisible();
+
+    /**
+     * @see ApplicationInfo#appComponentFactory
+     * @see R.styleable#AndroidManifestApplication_appComponentFactory
+     */
+    @Nullable
+    String getAppComponentFactory();
+
+    /**
+     * @see ApplicationInfo#AUTO_REVOKE_ALLOWED
+     * @see ApplicationInfo#AUTO_REVOKE_DISCOURAGED
+     * @see ApplicationInfo#AUTO_REVOKE_DISALLOWED
+     */
+    int getAutoRevokePermissions();
+
+    /**
+     * @see ApplicationInfo#backupAgentName
+     * @see R.styleable#AndroidManifestApplication_backupAgent
+     */
+    @Nullable
+    String getBackupAgentName();
+
+    /**
+     * @see ApplicationInfo#banner
+     * @see R.styleable#AndroidManifestApplication_banner
+     */
+    int getBanner();
+
+    /**
+     * @see ApplicationInfo#sourceDir
+     * @see ApplicationInfo#getBaseCodePath
+     */
+    @NonNull
+    String getBaseApkPath();
+
+    /**
+     * @see ApplicationInfo#category
+     * @see R.styleable#AndroidManifestApplication_appCategory
+     */
+    int getCategory();
+
+    /**
+     * @see ApplicationInfo#classLoaderName
+     * @see R.styleable#AndroidManifestApplication_classLoader
+     */
+    @Nullable
+    String getClassLoaderName();
+
+    /**
+     * @see ApplicationInfo#className
+     * @see R.styleable#AndroidManifestApplication_name
+     */
+    @Nullable
+    String getClassName();
+
+    /**
+     * @see ApplicationInfo#compatibleWidthLimitDp
+     * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp
+     */
+    int getCompatibleWidthLimitDp();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersion
+     * @see R.styleable#AndroidManifest_compileSdkVersion
+     */
+    int getCompileSdkVersion();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersionCodename
+     * @see R.styleable#AndroidManifest_compileSdkVersionCodename
+     */
+    @Nullable
+    String getCompileSdkVersionCodeName();
+
+    /**
+     * @see ApplicationInfo#dataExtractionRulesRes
+     * @see R.styleable#AndroidManifestApplication_dataExtractionRules
+     */
+    int getDataExtractionRules();
+
+    /**
+     * @see ApplicationInfo#descriptionRes
+     * @see R.styleable#AndroidManifestApplication_description
+     */
+    int getDescriptionRes();
+
+    /**
+     * @see ApplicationInfo#fullBackupContent
+     * @see R.styleable#AndroidManifestApplication_fullBackupContent
+     */
+    int getFullBackupContent();
+
+    /**
+     * @see ApplicationInfo#getGwpAsanMode()
+     * @see R.styleable#AndroidManifestApplication_gwpAsanMode
+     */
+    @ApplicationInfo.GwpAsanMode
+    int getGwpAsanMode();
+
+    /**
+     * @see ApplicationInfo#iconRes
+     * @see R.styleable#AndroidManifestApplication_icon
+     */
+    int getIconRes();
+
+    /**
+     * @see ApplicationInfo#installLocation
+     * @see R.styleable#AndroidManifest_installLocation
+     */
+    int getInstallLocation();
+
+    /**
+     * @see ApplicationInfo#labelRes
+     * @see R.styleable#AndroidManifestApplication_label
+     */
+    int getLabelRes();
+
+    /**
+     * @see ApplicationInfo#largestWidthLimitDp
+     * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
+     */
+    int getLargestWidthLimitDp();
+
+    /**
+     * @see ApplicationInfo#logo
+     * @see R.styleable#AndroidManifestApplication_logo
+     */
+    int getLogo();
+
+    /**
+     * @see ApplicationInfo#longVersionCode
+     */
+    long getLongVersionCode();
+
+    /**
+     * @see ApplicationInfo#manageSpaceActivityName
+     * @see R.styleable#AndroidManifestApplication_manageSpaceActivity
+     */
+    @Nullable
+    String getManageSpaceActivityName();
+
+    /**
+     * @see ApplicationInfo#maxAspectRatio
+     * @see R.styleable#AndroidManifestApplication_maxAspectRatio
+     */
+    float getMaxAspectRatio();
+
+    /**
+     * @see ApplicationInfo#getMemtagMode()
+     * @see R.styleable#AndroidManifestApplication_memtagMode
+     */
+    @ApplicationInfo.MemtagMode
+    int getMemtagMode();
+
+    /**
+     * @see ApplicationInfo#minAspectRatio
+     * @see R.styleable#AndroidManifestApplication_minAspectRatio
+     */
+    float getMinAspectRatio();
+
+    /**
+     * @see ApplicationInfo#minSdkVersion
+     * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion
+     */
+    int getMinSdkVersion();
+
+    /**
+     * @see ApplicationInfo#getNativeHeapZeroInitialized()
+     * @see R.styleable#AndroidManifestApplication_nativeHeapZeroInitialized
+     */
+    @ApplicationInfo.NativeHeapZeroInitialized
+    int getNativeHeapZeroInitialized();
+
+    /**
+     * @see ApplicationInfo#networkSecurityConfigRes
+     * @see R.styleable#AndroidManifestApplication_networkSecurityConfig
+     */
+    int getNetworkSecurityConfigRes();
+
+    /**
+     * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
+     * Otherwise, it's stored as {@link #getLabelRes()}.
+     *
+     * @see ApplicationInfo#nonLocalizedLabel
+     * @see R.styleable#AndroidManifestApplication_label
+     */
+    @Nullable
+    CharSequence getNonLocalizedLabel();
+
+    /**
+     * @see ApplicationInfo#scanSourceDir
+     * @see ApplicationInfo#getCodePath
+     */
+    @NonNull
+    String getPath();
+
+    /**
+     * @see ApplicationInfo#permission
+     * @see R.styleable#AndroidManifestApplication_permission
+     */
+    @Nullable
+    String getPermission();
+
+    /**
+     * @see ApplicationInfo#processName
+     * @see R.styleable#AndroidManifestApplication_process
+     */
+    @NonNull
+    String getProcessName();
+
+    /**
+     * @see ApplicationInfo#requiresSmallestWidthDp
+     * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
+     */
+    int getRequiresSmallestWidthDp();
+
+    /**
+     * Whether or not the app requested explicitly resizeable Activities. Null value means nothing
+     * was explicitly requested.
+     *
+     * @see ApplicationInfo#PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+     * @see ApplicationInfo#PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE
+     */
+    @Nullable
+    Boolean getResizeableActivity();
+
+    /**
+     * @see ApplicationInfo#roundIconRes
+     * @see R.styleable#AndroidManifestApplication_roundIcon
+     */
+    int getRoundIconRes();
+
+    /**
+     * @see ApplicationInfo#splitClassLoaderNames
+     * @see R.styleable#AndroidManifestApplication_classLoader
+     */
+    @Nullable
+    String[] getSplitClassLoaderNames();
+
+    /**
+     * @see ApplicationInfo#splitSourceDirs
+     * @see ApplicationInfo#getSplitCodePaths
+     */
+    @Nullable
+    String[] getSplitCodePaths();
+
+    /**
+     * @see ApplicationInfo#splitDependencies
+     */
+    @Nullable
+    SparseArray<int[]> getSplitDependencies();
+
+    /**
+     * @see ApplicationInfo#targetSdkVersion
+     * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion
+     */
+    int getTargetSdkVersion();
+
+    /**
+     * @see ApplicationInfo#targetSandboxVersion
+     * @see R.styleable#AndroidManifest_targetSandboxVersion
+     */
+    int getTargetSandboxVersion();
+
+    /**
+     * @see ApplicationInfo#taskAffinity
+     * @see R.styleable#AndroidManifestApplication_taskAffinity
+     */
+    @Nullable
+    String getTaskAffinity();
+
+    /**
+     * @see ApplicationInfo#theme
+     * @see R.styleable#AndroidManifestApplication_theme
+     */
+    int getTheme();
+
+    /**
+     * @see ApplicationInfo#uiOptions
+     * @see R.styleable#AndroidManifestApplication_uiOptions
+     */
+    int getUiOptions();
+
+    /**
+     * @see ApplicationInfo#volumeUuid
+     */
+    @Nullable
+    String getVolumeUuid();
+
+    /**
+     * @see ApplicationInfo#zygotePreloadName
+     */
+    @Nullable
+    String getZygotePreloadName();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION
+     * @see R.styleable#AndroidManifestApplication_requestForegroundServiceExemption
+     */
+    boolean hasRequestForegroundServiceExemption();
+
+    /**
+     * @see ApplicationInfo#getRequestRawExternalStorageAccess()
+     * @see R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess
+     */
+    Boolean hasRequestRawExternalStorageAccess();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE
+     */
+    boolean isAllowAudioPlaybackCapture();
+
+    /**
+     * @see ApplicationInfo#FLAG_ALLOW_BACKUP
+     */
+    boolean isAllowBackup();
+
+    /**
+     * @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA
+     */
+    boolean isAllowClearUserData();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
+     */
+    boolean isAllowClearUserDataOnFailedRestore();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING
+     */
+    boolean isAllowNativeHeapPointerTagging();
+
+    /**
+     * @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING
+     */
+    boolean isAllowTaskReparenting();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
+     * android.os.Build.VERSION_CODES#DONUT}.
+     *
+     * @see R.styleable#AndroidManifestSupportsScreens_anyDensity
+     * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES
+     */
+    boolean isAnyDensity();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND
+     */
+    boolean isBackupInForeground();
+
+    /**
+     * @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED
+     */
+    boolean isBaseHardwareAccelerated();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE
+     */
+    boolean isCantSaveState();
+
+    /**
+     * @see ApplicationInfo#crossProfile
+     */
+    boolean isCrossProfile();
+
+    /**
+     * @see ApplicationInfo#FLAG_DEBUGGABLE
+     */
+    boolean isDebuggable();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE
+     */
+    boolean isDefaultToDeviceProtectedStorage();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE
+     */
+    boolean isDirectBootAware();
+
+    /**
+     * @see ApplicationInfo#enabled
+     * @see R.styleable#AndroidManifestApplication_enabled
+     */
+    boolean isEnabled();
+
+    /**
+     * @see ApplicationInfo#FLAG_EXTERNAL_STORAGE
+     */
+    boolean isExternalStorage();
+
+    /**
+     * @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS
+     */
+    boolean isExtractNativeLibs();
+
+    /**
+     * @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY
+     */
+    boolean isFullBackupOnly();
+
+    /**
+     * @see ApplicationInfo#FLAG_HAS_CODE
+     */
+    boolean isHasCode();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS
+     */
+    boolean isHasDomainUrls();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
+     */
+    boolean isHasFragileUserData();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
+     */
+    boolean isIsolatedSplitLoading();
+
+    /**
+     * @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE
+     */
+    boolean isKillAfterRestore();
+
+    /**
+     * @see ApplicationInfo#FLAG_LARGE_HEAP
+     */
+    boolean isLargeHeap();
+
+    /**
+     * @see ApplicationInfo#FLAG_MULTIARCH
+     */
+    boolean isMultiArch();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY
+     * @see ApplicationInfo#isResourceOverlay()
+     */
+    boolean isOverlay();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE
+     */
+    boolean isPartiallyDirectBootAware();
+
+    /**
+     * @see ApplicationInfo#FLAG_PERSISTENT
+     */
+    boolean isPersistent();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_EXT_PROFILEABLE
+     */
+    boolean isProfileable();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL
+     */
+    boolean isProfileableByShell();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE
+     */
+    boolean isRequestLegacyExternalStorage();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
+     * android.os.Build.VERSION_CODES#DONUT}.
+     *
+     * @see R.styleable#AndroidManifestSupportsScreens_resizeable
+     * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS
+     */
+    boolean isResizeable();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
+     */
+    boolean isResizeableActivityViaSdkVersion();
+
+    /**
+     * @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION
+     */
+    boolean isRestoreAnyVersion();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY
+     */
+    boolean isStaticSharedLibrary();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
+     * android.os.Build.VERSION_CODES#GINGERBREAD}.
+     *
+     * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
+     */
+    boolean isSupportsExtraLargeScreens();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
+     * android.os.Build.VERSION_CODES#DONUT}.
+     *
+     * @see R.styleable#AndroidManifestSupportsScreens_largeScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
+     */
+    boolean isSupportsLargeScreens();
+
+    /**
+     * If omitted from manifest, returns true.
+     *
+     * @see R.styleable#AndroidManifestSupportsScreens_normalScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
+     */
+    boolean isSupportsNormalScreens();
+
+    /**
+     * @see ApplicationInfo#FLAG_SUPPORTS_RTL
+     */
+    boolean isSupportsRtl();
+
+    /**
+     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
+     * android.os.Build.VERSION_CODES#DONUT}.
+     *
+     * @see R.styleable#AndroidManifestSupportsScreens_smallScreens
+     * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
+     */
+    boolean isSupportsSmallScreens();
+
+    /**
+     * @see ApplicationInfo#FLAG_TEST_ONLY
+     */
+    boolean isTestOnly();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX
+     */
+    boolean isUseEmbeddedDex();
+
+    /**
+     * @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC
+     */
+    boolean isUsesCleartextTraffic();
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API
+     */
+    boolean isUsesNonSdkApi();
+
+    /**
+     * @see ApplicationInfo#FLAG_VM_SAFE_MODE
+     */
+    boolean isVmSafeMode();
+}
diff --git a/core/java/android/content/pm/parsing/PkgWithoutStatePackageInfo.java b/core/java/android/content/pm/parsing/PkgWithoutStatePackageInfo.java
new file mode 100644
index 0000000..b10e6fe5
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PkgWithoutStatePackageInfo.java
@@ -0,0 +1,238 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+
+import com.android.internal.R;
+
+import java.util.List;
+
+/**
+ * Container for fields that are eventually exposed through {@link PackageInfo}.
+ * <p>
+ * The following are dependent on system state and explicitly removed from this interface. They must
+ * be accessed by other means:
+ * <ul>
+ *    <li>{@link PackageInfo#firstInstallTime}</li>
+ *    <li>{@link PackageInfo#lastUpdateTime}</li>
+ *    <li>{@link PackageInfo#gids}</li>
+ * </ul>
+ * The following are derived from other fields and thus not provided specifically:
+ * <ul>
+ *    <li>{@link PackageInfo#requestedPermissionsFlags}</li>
+ * </ul>
+ * The following were deprecated at migration time and thus removed from this interface:
+ * <ul>
+ *    <li>{@link PackageInfo#mOverlayIsStatic}</li>
+ *    <li>{@link PackageInfo#overlayCategory}</li>
+ *    <li>{@link PackageInfo#overlayPriority}</li>
+ *    <li>{@link PackageInfo#overlayTarget}</li>
+ *    <li>{@link PackageInfo#signatures}</li>
+ *    <li>{@link PackageInfo#targetOverlayableName}</li>
+ *    <li>{@link PackageInfo#versionCodeMajor}</li>
+ *    <li>{@link PackageInfo#versionCode}</li>
+ * </ul>
+ * The following are retrieved through other APIs:
+ * <ul>
+ *    <li>{@link PackageInfo#signingInfo}</li>
+ *    <li>{@link PackageInfo#isApex}</li>
+ * </ul>
+ *
+ * @hide
+ */
+public interface PkgWithoutStatePackageInfo {
+
+    /**
+     * @see ActivityInfo
+     * @see PackageInfo#activities
+     */
+    @NonNull
+    List<ParsedActivity> getActivities();
+
+    /**
+     * @see PackageInfo#baseRevisionCode
+     */
+    int getBaseRevisionCode();
+
+    /**
+     * @see PackageInfo#compileSdkVersion
+     * @see R.styleable#AndroidManifest_compileSdkVersion
+     */
+    int getCompileSdkVersion();
+
+    /**
+     * @see ApplicationInfo#compileSdkVersionCodename
+     * @see R.styleable#AndroidManifest_compileSdkVersionCodename
+     */
+    @Nullable
+    String getCompileSdkVersionCodeName();
+
+    /**
+     * @see PackageInfo#configPreferences
+     * @see R.styleable#AndroidManifestUsesConfiguration
+     */
+    @NonNull
+    List<ConfigurationInfo> getConfigPreferences();
+
+    /**
+     * @see PackageInfo#featureGroups
+     * @see R.styleable#AndroidManifestUsesFeature
+     */
+    @NonNull
+    List<FeatureGroupInfo> getFeatureGroups();
+
+    /**
+     * @see InstrumentationInfo
+     * @see PackageInfo#instrumentation
+     */
+    @NonNull
+    List<ParsedInstrumentation> getInstrumentations();
+
+    /**
+     * @see PackageInfo#getLongVersionCode()
+     */
+    long getLongVersionCode();
+
+    /**
+     * @see PackageInfo#packageName
+     */
+    String getPackageName();
+
+    /**
+     * @see PermissionInfo
+     * @see PackageInfo#permissions
+     */
+    @NonNull
+    List<ParsedPermission> getPermissions();
+
+    /**
+     * @see ProviderInfo
+     * @see PackageInfo#providers
+     */
+    @NonNull
+    List<ParsedProvider> getProviders();
+
+    /**
+     * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even
+     * though they represent different functionality. TODO(b/135203078): Reconsider this and maybe
+     * make ParsedReceiver so it's not so confusing
+     *
+     * @see ActivityInfo
+     * @see PackageInfo#receivers
+     */
+    @NonNull
+    List<ParsedActivity> getReceivers();
+
+    /**
+     * @see PackageInfo#reqFeatures
+     * @see R.styleable#AndroidManifestUsesFeature
+     */
+    @NonNull
+    List<FeatureInfo> getRequestedFeatures();
+
+    /**
+     * All the permissions declared. This is an effective set, and may include permissions
+     * transformed from split/migrated permissions from previous versions, so may not be exactly
+     * what the package declares in its manifest.
+     *
+     * @see PackageInfo#requestedPermissions
+     * @see R.styleable#AndroidManifestUsesPermission
+     */
+    @NonNull
+    List<String> getRequestedPermissions();
+
+    /**
+     * The required account type without which this application will not function.
+     *
+     * @see PackageInfo#requiredAccountType
+     * @see R.styleable#AndroidManifestApplication_requiredAccountType
+     */
+    @Nullable
+    String getRequiredAccountType();
+
+    /**
+     * The restricted account authenticator type that is used by this application
+     *
+     * @see PackageInfo#restrictedAccountType
+     * @see R.styleable#AndroidManifestApplication_restrictedAccountType
+     */
+    @Nullable
+    String getRestrictedAccountType();
+
+    /**
+     * @see ServiceInfo
+     * @see PackageInfo#services
+     */
+    @NonNull
+    List<ParsedService> getServices();
+
+    /**
+     * @see PackageInfo#sharedUserId
+     * @see R.styleable#AndroidManifest_sharedUserId
+     */
+    @Nullable
+    String getSharedUserId();
+
+    /**
+     * @see PackageInfo#sharedUserLabel
+     * @see R.styleable#AndroidManifest_sharedUserLabel
+     */
+    int getSharedUserLabel();
+
+    /**
+     * TODO(b/135203078): Move split stuff to an inner data class
+     *
+     * @see ApplicationInfo#splitNames
+     * @see PackageInfo#splitNames
+     */
+    @Nullable
+    String[] getSplitNames();
+
+    /**
+     * @see PackageInfo#splitRevisionCodes
+     */
+    int[] getSplitRevisionCodes();
+
+    /**
+     * @see PackageInfo#versionName
+     */
+    @Nullable
+    String getVersionName();
+
+    /**
+     * @see PackageInfo#requiredForAllUsers
+     * @see R.styleable#AndroidManifestApplication_requiredForAllUsers
+     */
+    boolean isRequiredForAllUsers();
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 73ee132..8ca86f1 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -21,8 +21,10 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static android.content.pm.parsing.ParsingPackageUtils.ASPECT_RATIO_NOT_SET;
 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;
@@ -66,11 +68,8 @@
     private int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     private int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
 
-    @Nullable
-    private Float maxAspectRatio;
-
-    @Nullable
-    private Float minAspectRatio;
+    private float maxAspectRatio = ASPECT_RATIO_NOT_SET;
+    private float minAspectRatio = ASPECT_RATIO_NOT_SET;
 
     private boolean supportsSizeChanges;
 
@@ -233,7 +232,7 @@
         return this;
     }
 
-    public ParsedActivity setMaxAspectRatio(Float maxAspectRatio) {
+    public ParsedActivity setMaxAspectRatio(float maxAspectRatio) {
         this.maxAspectRatio = maxAspectRatio;
         return this;
     }
@@ -259,7 +258,7 @@
         return this;
     }
 
-    public ParsedActivity setMinAspectRatio(Float minAspectRatio) {
+    public ParsedActivity setMinAspectRatio(float minAspectRatio) {
         this.minAspectRatio = minAspectRatio;
         return this;
     }
@@ -374,8 +373,8 @@
         dest.writeInt(this.lockTaskLaunchMode);
         dest.writeInt(this.screenOrientation);
         dest.writeInt(this.resizeMode);
-        dest.writeValue(this.maxAspectRatio);
-        dest.writeValue(this.minAspectRatio);
+        dest.writeFloat(this.maxAspectRatio);
+        dest.writeFloat(this.minAspectRatio);
         dest.writeBoolean(this.supportsSizeChanges);
         dest.writeString(this.requestedVrComponent);
         dest.writeInt(this.rotationAnimation);
@@ -411,8 +410,8 @@
         this.lockTaskLaunchMode = in.readInt();
         this.screenOrientation = in.readInt();
         this.resizeMode = in.readInt();
-        this.maxAspectRatio = (Float) in.readValue(Float.class.getClassLoader());
-        this.minAspectRatio = (Float) in.readValue(Float.class.getClassLoader());
+        this.maxAspectRatio = in.readFloat();
+        this.minAspectRatio = in.readFloat();
         this.supportsSizeChanges = in.readBoolean();
         this.requestedVrComponent = in.readString();
         this.rotationAnimation = in.readInt();
@@ -423,6 +422,7 @@
         }
     }
 
+    @NonNull
     public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
         @Override
         public ParsedActivity createFromParcel(Parcel source) {
@@ -503,20 +503,14 @@
         return resizeMode;
     }
 
-    @Nullable
-    public Float getMaxAspectRatio() {
+    public float getMaxAspectRatio() {
         return maxAspectRatio;
     }
 
-    @Nullable
-    public Float getMinAspectRatio() {
+    public float getMinAspectRatio() {
         return minAspectRatio;
     }
 
-    public boolean getSupportsSizeChanges() {
-        return supportsSizeChanges;
-    }
-
     @Nullable
     public String getRequestedVrComponent() {
         return requestedVrComponent;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index ac6bcd0..dc7eb80 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.parsing.ParsingUtils.NOT_SET;
 import static android.content.pm.parsing.component.ComponentParseUtils.flag;
 
 import android.annotation.NonNull;
@@ -269,15 +270,15 @@
                     activity, tag, null, pkg, sa, 0, useRoundIcon, input,
                     R.styleable.AndroidManifestActivityAlias_banner,
                     R.styleable.AndroidManifestActivityAlias_description,
-                    null /*directBootAwareAttr*/,
+                    NOT_SET /*directBootAwareAttr*/,
                     R.styleable.AndroidManifestActivityAlias_enabled,
                     R.styleable.AndroidManifestActivityAlias_icon,
                     R.styleable.AndroidManifestActivityAlias_label,
                     R.styleable.AndroidManifestActivityAlias_logo,
                     R.styleable.AndroidManifestActivityAlias_name,
-                    null /*processAttr*/,
+                    NOT_SET /*processAttr*/,
                     R.styleable.AndroidManifestActivityAlias_roundIcon,
-                    null /*splitNameAttr*/,
+                    NOT_SET /*splitNameAttr*/,
                     R.styleable.AndroidManifestActivityAlias_attributionTags);
             if (result.isError()) {
                 return result;
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/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
index ab596d3..6d798fd 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
@@ -16,8 +16,9 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
 import android.content.pm.parsing.ParsingPackage;
@@ -41,9 +42,8 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     static <Component extends ParsedComponent> ParseResult<Component> parseComponent(
             Component component, String tag, ParsingPackage pkg, TypedArray array,
-            boolean useRoundIcon, ParseInput input, int bannerAttr,
-            @Nullable Integer descriptionAttr, int iconAttr, int labelAttr, int logoAttr,
-            int nameAttr, int roundIconAttr) {
+            boolean useRoundIcon, ParseInput input, int bannerAttr, int descriptionAttr,
+            int iconAttr, int labelAttr, int logoAttr, int nameAttr, int roundIconAttr) {
         String name = array.getNonConfigurationString(nameAttr, 0);
         if (TextUtils.isEmpty(name)) {
             return input.error(tag + " does not specify android:name");
@@ -81,7 +81,7 @@
             component.setBanner(bannerVal);
         }
 
-        if (descriptionAttr != null) {
+        if (descriptionAttr != NOT_SET) {
             component.setDescriptionRes(array.getResourceId(descriptionAttr, 0));
         }
 
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/ParsedInstrumentationUtils.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
index 5977c83..f122fd6 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
@@ -16,15 +16,17 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+
 import android.annotation.NonNull;
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 
 import com.android.internal.R;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -46,7 +48,7 @@
             ParseResult<ParsedInstrumentation> result = ParsedComponentUtils.parseComponent(
                     instrumentation, tag, pkg, sa, useRoundIcon, input,
                     R.styleable.AndroidManifestInstrumentation_banner,
-                    null /*descriptionAttr*/,
+                    NOT_SET /*descriptionAttr*/,
                     R.styleable.AndroidManifestInstrumentation_icon,
                     R.styleable.AndroidManifestInstrumentation_label,
                     R.styleable.AndroidManifestInstrumentation_logo,
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/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
index 7ccca93..869e81c 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
@@ -16,8 +16,9 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.IntentFilter;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.ParsingUtils;
@@ -45,11 +46,10 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     static <Component extends ParsedMainComponent> ParseResult<Component> parseMainComponent(
             Component component, String tag, String[] separateProcesses, ParsingPackage pkg,
-            TypedArray array, int flags, boolean useRoundIcon, ParseInput input,
-            int bannerAttr, int descriptionAttr, @Nullable Integer directBootAwareAttr,
-            @Nullable Integer enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr,
-            @Nullable Integer processAttr, int roundIconAttr, @Nullable Integer splitNameAttr,
-            @Nullable Integer attributionTagsAttr) {
+            TypedArray array, int flags, boolean useRoundIcon, ParseInput input, int bannerAttr,
+            int descriptionAttr, int directBootAwareAttr, int enabledAttr, int iconAttr,
+            int labelAttr, int logoAttr, int nameAttr, int processAttr, int roundIconAttr,
+            int splitNameAttr, int attributionTagsAttr) {
         ParseResult<Component> result = ParsedComponentUtils.parseComponent(component, tag, pkg,
                 array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr,
                 logoAttr, nameAttr, roundIconAttr);
@@ -57,18 +57,18 @@
             return result;
         }
 
-        if (directBootAwareAttr != null) {
+        if (directBootAwareAttr != NOT_SET) {
             component.setDirectBootAware(array.getBoolean(directBootAwareAttr, false));
             if (component.isDirectBootAware()) {
                 pkg.setPartiallyDirectBootAware(true);
             }
         }
 
-        if (enabledAttr != null) {
+        if (enabledAttr != NOT_SET) {
             component.setEnabled(array.getBoolean(enabledAttr, true));
         }
 
-        if (processAttr != null) {
+        if (processAttr != NOT_SET) {
             CharSequence processName;
             if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
                 processName = array.getNonConfigurationString(processAttr,
@@ -91,11 +91,11 @@
             component.setProcessName(processNameResult.getResult());
         }
 
-        if (splitNameAttr != null) {
+        if (splitNameAttr != NOT_SET) {
             component.setSplitName(array.getNonConfigurationString(splitNameAttr, 0));
         }
 
-        if (attributionTagsAttr != null) {
+        if (attributionTagsAttr != NOT_SET) {
             final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0);
             if (attributionTags != null) {
                 component.setAttributionTags(attributionTags.split("\\|"));
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/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index eec333c..5a7a5ef 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -16,6 +16,8 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+
 import android.annotation.NonNull;
 import android.content.pm.PermissionInfo;
 import android.content.pm.parsing.ParsingPackage;
@@ -163,7 +165,7 @@
             result = ParsedComponentUtils.parseComponent(
                     permission, tag, pkg, sa, useRoundIcon, input,
                     R.styleable.AndroidManifestPermissionTree_banner,
-                    null /*descriptionAttr*/,
+                    NOT_SET /*descriptionAttr*/,
                     R.styleable.AndroidManifestPermissionTree_icon,
                     R.styleable.AndroidManifestPermissionTree_label,
                     R.styleable.AndroidManifestPermissionTree_logo,
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/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
index d4e19af..54dd295 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
@@ -101,7 +101,7 @@
             proc.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1));
             proc.setMemtagMode(sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1));
             if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized)) {
-                Boolean v = sa.getBoolean(
+                final boolean v = sa.getBoolean(
                         R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized, false);
                 proc.setNativeHeapZeroInitialized(
                         v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
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/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/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index 324612d..1a3fc85 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -16,6 +16,8 @@
 
 package android.content.pm.parsing.result;
 
+import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -62,7 +64,7 @@
     private ArrayMap<Long, String> mDeferredErrors = null;
 
     private String mPackageName;
-    private Integer mTargetSdkVersion;
+    private int mTargetSdkVersion = NOT_SET;
 
     /**
      * Specifically for {@link PackageManager#getPackageArchiveInfo(String, int)} where
@@ -119,7 +121,7 @@
             // how many APKs they're going through.
             mDeferredErrors.erase();
         }
-        mTargetSdkVersion = null;
+        mTargetSdkVersion = NOT_SET;
         return this;
     }
 
@@ -139,7 +141,7 @@
         if (DEBUG_THROW_ALL_ERRORS) {
             return error(parseError);
         }
-        if (mTargetSdkVersion != null) {
+        if (mTargetSdkVersion != NOT_SET) {
             if (mDeferredErrors != null && mDeferredErrors.containsKey(deferredError)) {
                 // If the map already contains the key, that means it's already been checked and
                 // found to be disabled. Otherwise it would've failed when mTargetSdkVersion was
diff --git a/core/java/android/content/pm/pkg/PackageUserState.java b/core/java/android/content/pm/pkg/PackageUserState.java
new file mode 100644
index 0000000..e5853f0
--- /dev/null
+++ b/core/java/android/content/pm/pkg/PackageUserState.java
@@ -0,0 +1,90 @@
+/*
+ * 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.content.pm.pkg;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The API surface for a {@link android.content.pm.PackageUserState}. Methods are expected to return
+ * immutable objects. This may mean copying data on each invocation until related classes are
+ * refactored to be immutable.
+ * <p>
+ * TODO: Replace implementation usage with the interface. Currently the name overlap is intentional.
+ * <p>
+ *
+ * @hide
+ */
+// TODO(b/173807334): Expose API
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface PackageUserState {
+    /**
+     * Credential encrypted /data partition inode.
+     */
+    long getCeDataInode();
+
+    @NonNull
+    Set<String> getDisabledComponents();
+
+    @PackageManager.DistractionRestriction
+    int getDistractionFlags();
+
+    @NonNull
+    Set<String> getEnabledComponents();
+
+    int getEnabledState();
+
+    @Nullable
+    String getHarmfulAppWarning();
+
+    @PackageManager.InstallReason
+    int getInstallReason();
+
+    @Nullable
+    String getLastDisableAppCaller();
+
+    @Nullable
+    OverlayPaths getOverlayPaths();
+
+    @NonNull
+    Map<String, OverlayPaths> getSharedLibraryOverlayPaths();
+
+    @PackageManager.UninstallReason
+    int getUninstallReason();
+
+    boolean isHidden();
+
+    boolean isInstalled();
+
+    boolean isInstantApp();
+
+    boolean isNotLaunched();
+
+    boolean isStopped();
+
+    boolean isSuspended();
+
+    boolean isVirtualPreload();
+}
diff --git a/core/java/android/content/res/TEST_MAPPING b/core/java/android/content/res/TEST_MAPPING
index c02af59..535afd36 100644
--- a/core/java/android/content/res/TEST_MAPPING
+++ b/core/java/android/content/res/TEST_MAPPING
@@ -2,7 +2,9 @@
   "presubmit": [
     {
       "name": "CtsResourcesLoaderTests"
-    },
+    }
+  ],
+  "presubmit-large": [
     {
       "name": "CtsContentTestCases",
       "options": [
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/android/uwb/SessionHandle.aidl b/core/java/android/debug/FingerprintAndPairDevice.aidl
similarity index 66%
copy from core/java/android/uwb/SessionHandle.aidl
copy to core/java/android/debug/FingerprintAndPairDevice.aidl
index 58a7dbb..b439e14 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/core/java/android/debug/FingerprintAndPairDevice.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
-package android.uwb;
+package android.debug;
 
-parcelable SessionHandle;
+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/android/uwb/AdapterState.aidl b/core/java/android/debug/IAdbCallback.aidl
similarity index 60%
rename from core/java/android/uwb/AdapterState.aidl
rename to core/java/android/debug/IAdbCallback.aidl
index 991f64a..9c8f1cf 100644
--- a/core/java/android/uwb/AdapterState.aidl
+++ b/core/java/android/debug/IAdbCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,25 +14,18 @@
  * limitations under the License.
  */
 
-package android.uwb;
+package android.debug;
+
+import android.debug.AdbTransportType;
 
 /**
+ * Callback interface of {@link android.debug.IAdbCallbackManager}.
+ *
  * @hide
  */
-@Backing(type="int")
-enum AdapterState {
- /**
-   * The state when UWB is disabled.
-   */
-  STATE_DISABLED,
-
-  /**
-   * The state when UWB is enabled but has no active sessions.
-   */
-  STATE_ENABLED_INACTIVE,
-
-  /**
-   * The state when UWB is enabled and has active sessions.
-   */
-  STATE_ENABLED_ACTIVE,
-}
\ No newline at end of file
+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/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 fa7ce11..3c524b2 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -33,6 +33,7 @@
 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
@@ -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.
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 3f3db29..c8c122d 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -438,9 +438,16 @@
     }
 
     private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
+        private final long mAuthRequestId;
+
+        OnAuthenticationCancelListener(long id) {
+            mAuthRequestId = id;
+        }
+
         @Override
         public void onCancel() {
-            cancelAuthentication();
+            Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId);
+            cancelAuthentication(mAuthRequestId);
         }
     }
 
@@ -853,10 +860,12 @@
      * @param userId The user to authenticate
      * @param operationId The keystore operation associated with authentication
      *
+     * @return A requestId that can be used to cancel this operation.
+     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void authenticateUserForOperation(
+    public long authenticateUserForOperation(
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback,
@@ -871,7 +880,8 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
-        authenticateInternal(operationId, cancel, executor, callback, userId);
+
+        return authenticateInternal(operationId, cancel, executor, callback, userId);
     }
 
     /**
@@ -1002,10 +1012,10 @@
         authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
     }
 
-    private void cancelAuthentication() {
+    private void cancelAuthentication(long requestId) {
         if (mService != null) {
             try {
-                mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+                mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to cancel authentication", e);
             }
@@ -1024,7 +1034,7 @@
         authenticateInternal(operationId, cancel, executor, callback, userId);
     }
 
-    private void authenticateInternal(
+    private long authenticateInternal(
             long operationId,
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
@@ -1040,9 +1050,7 @@
         try {
             if (cancel.isCanceled()) {
                 Log.w(TAG, "Authentication already canceled");
-                return;
-            } else {
-                cancel.setOnCancelListener(new OnAuthenticationCancelListener());
+                return -1;
             }
 
             mExecutor = executor;
@@ -1065,14 +1073,16 @@
                 promptInfo = mPromptInfo;
             }
 
-            mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver,
-                    mContext.getOpPackageName(), promptInfo);
-
+            final long authId = mService.authenticate(mToken, operationId, userId,
+                    mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo);
+            cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
+            return authId;
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception while authenticating", e);
             mExecutor.execute(() -> callback.onAuthenticationError(
                     BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                     mContext.getString(R.string.biometric_error_hw_unavailable)));
+            return -1;
         }
     }
 
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 4c2a9ae..91f794c 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -41,13 +41,14 @@
     // Retrieve the package where BIometricOrompt's UI is implemented
     String getUiPackage();
 
-    // Requests authentication. The service choose the appropriate biometric to use, and show
-    // the corresponding BiometricDialog.
-    void authenticate(IBinder token, long sessionId, int userId,
+    // Requests authentication. The service chooses the appropriate biometric to use, and shows
+    // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
+    // this operation.
+    long authenticate(IBinder token, long sessionId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
 
-    // Cancel authentication for the given sessionId
-    void cancelAuthentication(IBinder token, String opPackageName);
+    // Cancel authentication for the given requestId.
+    void cancelAuthentication(IBinder token, String opPackageName, long requestId);
 
     // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
     // Checks if biometrics can be used.
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index 876513f..addd622 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -48,13 +48,13 @@
     // startPreparedClient().
     void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie, boolean allowBackgroundAuthentication);
+            long requestId, int cookie, boolean allowBackgroundAuthentication);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int cookie);
 
-    // Cancels authentication.
-    void cancelAuthenticationFromService(IBinder token, String opPackageName);
+    // Cancels authentication for the given requestId.
+    void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId);
 
     // Determine if HAL is loaded and ready
     boolean isHardwareDetected(String opPackageName);
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 64b5118..2c3c8c3 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -36,13 +36,14 @@
     // Retrieve static sensor properties for all biometric sensors
     List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
 
-    // Requests authentication. The service choose the appropriate biometric to use, and show
-    // the corresponding BiometricDialog.
-    void authenticate(IBinder token, long operationId, int userId,
+    // Requests authentication. The service chooses the appropriate biometric to use, and shows
+    // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
+    // this operation.
+    long authenticate(IBinder token, long operationId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
 
-    // Cancel authentication for the given session.
-    void cancelAuthentication(IBinder token, String opPackageName);
+    // Cancel authentication for the given requestId.
+    void cancelAuthentication(IBinder token, String opPackageName, long requestId);
 
     // Checks if biometrics can be used.
     int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);
diff --git a/core/java/android/hardware/biometrics/OWNERS b/core/java/android/hardware/biometrics/OWNERS
index 2065ffa..0b4d9d9 100644
--- a/core/java/android/hardware/biometrics/OWNERS
+++ b/core/java/android/hardware/biometrics/OWNERS
@@ -1,8 +1,3 @@
 # Bug component: 879035
 
-curtislb@google.com
-ilyamaty@google.com
-jaggies@google.com
-joshmccloskey@google.com
-kchyn@google.com
-
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index af48b71..3c1ec3e 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -807,6 +807,23 @@
      * The same logic applies to other hardware levels and capabilities.
      * </p>
      *
+     * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
+     * which clients can take advantage of : </p>
+     * <table>
+     * <tr><th colspan="10">Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</th></tr>
+     * <tr> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th>  <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr>
+     * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td colspan="3" id="rb"></td> <td>Ultra high res still image capture with preview</td> </tr>
+     * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code RECORD}</td> <td>Ultra high res still capture with preview + app based RECORD size analysis</td> </tr>
+     * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG / YUV / RAW}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code MAX}</td> <td>Ultra high res still image capture with preview + default sensor pixel mode analysis stream</td> </tr>
+     * </table><br>
+     *
+     * <p> Here, SC Map, refers to the {@link StreamConfigurationMap}, the target stream sizes must
+     * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link
+     * StreamConfigurationMap} and {@code MAX_RES} refers to the maximum resolution {@link
+     * StreamConfigurationMap}. The same capture request must not mix targets from
+     * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes.
+     *
      * <p>Since the capabilities of camera devices vary greatly, a given camera device may support
      * target combinations with sizes outside of these guarantees, but this can only be tested for
      * by calling {@link #isSessionConfigurationSupported} or attempting to create a session with
@@ -989,6 +1006,16 @@
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>Maximum-resolution two-input ZSL in-app processing.</td> </tr>
      * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>ZSL still capture and in-app processing.</td> </tr>
      * </table><br>
+     * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
+     * which clients can take advantage of : </p>
+     * <table>
+     * <tr><th colspan="13">Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors (YUV / PRIV inputs are guaranteed only if YUV / PRIVATE reprocessing are supported)</th></tr>
+     * <tr> <th colspan="3" id="rb">Input</th> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th>  <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th><th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr>
+     * <tr> <td>{@code RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td>{@code RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td colspan="3" id="rb"></td> <td>RAW remosaic reprocessing with seperate preview</td> </tr>
+     * <tr> <td>{@code RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td>{@code RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG / YUV}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td> <td>Ultra high res RAW -> JPEG / YUV with seperate preview</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code YUV / PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG }</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td> <td> Ultra high res PRIV / YUV -> YUV / JPEG reprocessing with seperate preview</td> </tr>
+     * </table><br>
      * No additional mandatory stream combinations for RAW capability and LEVEL-3 hardware level.
      * </p>
      *
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index d9fa56e..4b35294 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1138,10 +1138,14 @@
      * <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}</code> describes the streams supported in 'default'
      * mode.
      * The stream configurations supported in 'max resolution' mode are described by
-     * <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION android.scaler.streamConfigurationMapMaximumResolution}</code>.</p>
+     * <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION android.scaler.streamConfigurationMapMaximumResolution}</code>.
+     * The maximum resolution mode pixel array size of a camera device
+     * (<code>{@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}</code>) with this capability,
+     * will be at least 24 megapixels.</p>
      *
      * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION
+     * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR = 16;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index b55a1cb..eab9d8b 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1022,7 +1022,8 @@
      * <p>which define a transform from input sensor colors, <code>P_in = [ r g b ]</code>,
      * to output linear sRGB, <code>P_out = [ r' g' b' ]</code>,</p>
      * <p>with colors as follows:</p>
-     * <pre><code>r' = I0r + I1g + I2b
+     * <pre><code>
+     * r' = I0r + I1g + I2b
      * g' = I3r + I4g + I5b
      * b' = I6r + I7g + I8b
      * </code></pre>
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/extension/IRequestProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/IRequestProcessorImpl.aidl
index 52595a8..88b03a47 100644
--- a/core/java/android/hardware/camera2/extension/IRequestProcessorImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/IRequestProcessorImpl.aidl
@@ -24,9 +24,9 @@
 interface IRequestProcessorImpl
 {
     void setImageProcessor(in OutputConfigId outputConfigId, in IImageProcessorImpl imageProcessor);
-    boolean submit(in Request request, in IRequestCallback callback);
-    boolean submitBurst(in List<Request> requests, in IRequestCallback callback);
-    boolean setRepeating(in Request request, in IRequestCallback callback);
+    int submit(in Request request, in IRequestCallback callback);
+    int submitBurst(in List<Request> requests, in IRequestCallback callback);
+    int setRepeating(in Request request, in IRequestCallback callback);
     void abortCaptures();
     void stopRepeating();
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index d5a35bc..8da6551 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -446,16 +446,12 @@
         }
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        if (mHandlerThread != null) {
-            mHandlerThread.quitSafely();
-        }
-        super.finalize();
-    }
+    public void release(boolean skipCloseNotification) {
+        boolean notifyClose = false;
 
-    public void release() {
         synchronized (mInterfaceLock) {
+            mHandlerThread.quitSafely();
+
             if (mSessionProcessor != null) {
                 try {
                     mSessionProcessor.deInitSession();
@@ -469,6 +465,7 @@
             if (mExtensionClientId >= 0) {
                 CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
                 if (mInitialized) {
+                    notifyClose = true;
                     CameraExtensionCharacteristics.releaseSession();
                 }
             }
@@ -482,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() {
@@ -491,7 +498,7 @@
             }
         }
 
-        release();
+        release(true /*skipCloseNotification*/);
 
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -507,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
@@ -865,14 +864,15 @@
         }
 
         @Override
-        public boolean submit(Request request, IRequestCallback callback) {
+        public int submit(Request request, IRequestCallback callback) {
             ArrayList<Request> captureList = new ArrayList<>();
             captureList.add(request);
             return submitBurst(captureList, callback);
         }
 
         @Override
-        public boolean submitBurst(List<Request> requests, IRequestCallback callback) {
+        public int submitBurst(List<Request> requests, IRequestCallback callback) {
+            int seqId = -1;
             synchronized (mInterfaceLock) {
                 try {
                     CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
@@ -881,37 +881,36 @@
                         captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
                                 mCameraConfigMap));
                     }
-                    mCaptureSession.captureBurstRequests(captureRequests,
+                    seqId = mCaptureSession.captureBurstRequests(captureRequests,
                             new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
                 } catch (CameraAccessException e) {
                     Log.e(TAG, "Failed to submit capture requests!");
-                    return false;
                 } catch (IllegalStateException e) {
                     Log.e(TAG, "Capture session closed!");
                 }
             }
 
-            return true;
+            return seqId;
         }
 
         @Override
-        public boolean setRepeating(Request request, IRequestCallback callback) {
+        public int setRepeating(Request request, IRequestCallback callback) {
+            int seqId = -1;
             synchronized (mInterfaceLock) {
                 try {
                     CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
                                 request, mCameraConfigMap);
                     CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
-                    mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+                    seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
                             new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
                 } catch (CameraAccessException e) {
                     Log.e(TAG, "Failed to enable repeating request!");
-                    return false;
                 } catch (IllegalStateException e) {
                     Log.e(TAG, "Capture session closed!");
                 }
             }
 
-            return true;
+            return seqId;
         }
 
         @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 0bf812e..4708f3e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -104,6 +104,9 @@
     private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
             new SparseArray<CaptureCallbackHolder>();
 
+    /** map request IDs which have batchedOutputs to requestCount*/
+    private HashMap<Integer, Integer> mBatchOutputMap = new HashMap<>();
+
     private int mRepeatingRequestId = REQUEST_ID_NONE;
     // Latest repeating request list's types
     private int[] mRepeatingRequestTypes;
@@ -697,12 +700,12 @@
             }
 
             if (mCurrentExtensionSession != null) {
-                mCurrentExtensionSession.release();
+                mCurrentExtensionSession.release(false /*skipCloseNotification*/);
                 mCurrentExtensionSession = null;
             }
 
             if (mCurrentAdvancedExtensionSession != null) {
-                mCurrentAdvancedExtensionSession.release();
+                mCurrentAdvancedExtensionSession.release(false /*skipCloseNotification*/);
                 mCurrentAdvancedExtensionSession = null;
             }
 
@@ -973,6 +976,7 @@
             mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null);
             mIdle = true;
             mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>();
+            mBatchOutputMap = new HashMap<>();
             mFrameNumberTracker = new FrameNumberTracker();
 
             mCurrentSession.closeWithoutDraining();
@@ -1179,6 +1183,41 @@
         return requestTypes;
     }
 
+    private boolean hasBatchedOutputs(List<CaptureRequest> requestList) {
+        boolean hasBatchedOutputs = true;
+        for (int i = 0; i < requestList.size(); i++) {
+            CaptureRequest request = requestList.get(i);
+            if (!request.isPartOfCRequestList()) {
+                hasBatchedOutputs = false;
+                break;
+            }
+            if (i == 0) {
+                Collection<Surface> targets = request.getTargets();
+                if (targets.size() != 2) {
+                    hasBatchedOutputs = false;
+                    break;
+                }
+            }
+        }
+        return hasBatchedOutputs;
+    }
+
+    private void updateTracker(int requestId, long frameNumber,
+            int requestType, CaptureResult result, boolean isPartialResult) {
+        int requestCount = 1;
+        // If the request has batchedOutputs update each frame within the batch.
+        if (mBatchOutputMap.containsKey(requestId)) {
+            requestCount = mBatchOutputMap.get(requestId);
+            for (int i = 0; i < requestCount; i++) {
+                mFrameNumberTracker.updateTracker(frameNumber - (requestCount - 1 - i),
+                        result, isPartialResult, requestType);
+            }
+        } else {
+            mFrameNumberTracker.updateTracker(frameNumber, result,
+                    isPartialResult, requestType);
+        }
+    }
+
     private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
             Executor executor, boolean repeating) throws CameraAccessException {
 
@@ -1224,6 +1263,14 @@
                 request.recoverStreamIdToSurface();
             }
 
+            // If the request has batched outputs, then store the
+            // requestCount and requestId in the map.
+            boolean hasBatchedOutputs = hasBatchedOutputs(requestList);
+            if (hasBatchedOutputs) {
+                int requestCount = requestList.size();
+                mBatchOutputMap.put(requestInfo.getRequestId(), requestCount);
+            }
+
             if (callback != null) {
                 mCaptureCallbackMap.put(requestInfo.getRequestId(),
                         new CaptureCallbackHolder(
@@ -1352,12 +1399,12 @@
             }
 
             if (mCurrentExtensionSession != null) {
-                mCurrentExtensionSession.release();
+                mCurrentExtensionSession.release(true /*skipCloseNotification*/);
                 mCurrentExtensionSession = null;
             }
 
             if (mCurrentAdvancedExtensionSession != null) {
-                mCurrentAdvancedExtensionSession.release();
+                mCurrentAdvancedExtensionSession.release(true /*skipCloseNotification*/);
                 mCurrentAdvancedExtensionSession = null;
             }
 
@@ -1839,8 +1886,18 @@
             if (DEBUG) {
                 Log.v(TAG, String.format("got error frame %d", frameNumber));
             }
-            mFrameNumberTracker.updateTracker(frameNumber,
-                    /*error*/true, request.getRequestType());
+
+            // Update FrameNumberTracker for every frame during HFR mode.
+            if (mBatchOutputMap.containsKey(requestId)) {
+                for (int i = 0; i < mBatchOutputMap.get(requestId); i++) {
+                    mFrameNumberTracker.updateTracker(frameNumber - (subsequenceId - i),
+                            /*error*/true, request.getRequestType());
+                }
+            } else {
+                mFrameNumberTracker.updateTracker(frameNumber,
+                        /*error*/true, request.getRequestType());
+            }
+
             checkAndFireSequenceComplete();
 
             // Dispatch the failure callback
@@ -2023,7 +2080,6 @@
         public void onResultReceived(CameraMetadataNative result,
                 CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
                 throws RemoteException {
-
             int requestId = resultExtras.getRequestId();
             long frameNumber = resultExtras.getFrameNumber();
 
@@ -2064,8 +2120,8 @@
                                         + frameNumber);
                     }
 
-                    mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
-                            requestType);
+                    updateTracker(requestId, frameNumber, requestType, /*result*/null,
+                            isPartialResult);
 
                     return;
                 }
@@ -2077,8 +2133,9 @@
                                         + frameNumber);
                     }
 
-                    mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
-                            requestType);
+                    updateTracker(requestId, frameNumber, requestType, /*result*/null,
+                            isPartialResult);
+
                     return;
                 }
 
@@ -2184,9 +2241,7 @@
                     Binder.restoreCallingIdentity(ident);
                 }
 
-                // Collect the partials for a total result; or mark the frame as totally completed
-                mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
-                        requestType);
+                updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult);
 
                 // Fire onCaptureSequenceCompleted
                 if (!isPartialResult) {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 7d29a7d..71047af 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -251,6 +251,7 @@
                     CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT);
             mPreviewImageProcessor.onResolutionUpdate(new Size(repeatingSurfaceInfo.mWidth,
                     repeatingSurfaceInfo.mHeight));
+            mPreviewImageProcessor.onOutputSurface(null, -1);
             mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
                     repeatingSurfaceInfo.mHeight,
                     CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, PREVIEW_QUEUE_SIZE,
@@ -630,18 +631,13 @@
                 new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler);
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        if (mHandlerThread != null) {
-            mHandlerThread.quitSafely();
-        }
-        super.finalize();
-    }
-
     /** @hide */
-    public void release() {
+    public void release(boolean skipCloseNotification) {
+        boolean notifyClose = false;
+
         synchronized (mInterfaceLock) {
             mInternalRepeatingRequestEnabled = false;
+            mHandlerThread.quitSafely();
 
             try {
                 mPreviewExtender.onDeInit();
@@ -654,6 +650,7 @@
             if (mExtensionClientId >= 0) {
                 CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
                 if (mInitialized) {
+                    notifyClose = true;
                     CameraExtensionCharacteristics.releaseSession();
                 }
             }
@@ -704,6 +701,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() {
@@ -713,7 +719,7 @@
             }
         }
 
-        release();
+        release(true /*skipCloseNotification*/);
 
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -745,14 +751,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
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 8fd9a6a..196134b 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1720,21 +1720,21 @@
                 new SetCommand() {
             @Override
             public <T> void setValue(CameraMetadataNative metadata, T value) {
-                metadata.setAWBRegions((MeteringRectangle[]) value);
+                metadata.setAWBRegions(value);
             }
         });
         sSetCommandMap.put(CaptureRequest.CONTROL_AF_REGIONS.getNativeKey(),
                 new SetCommand() {
             @Override
             public <T> void setValue(CameraMetadataNative metadata, T value) {
-                metadata.setAFRegions((MeteringRectangle[]) value);
+                metadata.setAFRegions(value);
             }
         });
         sSetCommandMap.put(CaptureRequest.CONTROL_AE_REGIONS.getNativeKey(),
                 new SetCommand() {
             @Override
             public <T> void setValue(CameraMetadataNative metadata, T value) {
-                metadata.setAERegions((MeteringRectangle[]) value);
+                metadata.setAERegions(value);
             }
         });
     }
@@ -1815,30 +1815,33 @@
         return true;
     }
 
-    private <T> boolean setAFRegions(MeteringRectangle[] afRegions) {
+    private <T> boolean setAFRegions(T afRegions) {
         if (afRegions == null) {
             return false;
         }
         setBase(CaptureRequest.CONTROL_AF_REGIONS_SET, true);
-        setBase(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
+        // 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(MeteringRectangle[] aeRegions) {
+    private <T> boolean setAERegions(T aeRegions) {
         if (aeRegions == null) {
             return false;
         }
         setBase(CaptureRequest.CONTROL_AE_REGIONS_SET, true);
-        setBase(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
         return true;
     }
 
-    private <T> boolean setAWBRegions(MeteringRectangle[] awbRegions) {
+    private <T> boolean setAWBRegions(T awbRegions) {
         if (awbRegions == null) {
             return false;
         }
         setBase(CaptureRequest.CONTROL_AWB_REGIONS_SET, true);
-        setBase(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
         return true;
     }
 
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/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 52dad3e..95892aa 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -75,23 +75,24 @@
     /**
      * Submits a {@link DeviceStateRequest request} to modify the device state.
      * <p>
-     * By default, the request is kept active until a call to
-     * {@link #cancelRequest(DeviceStateRequest)} or until one of the following occurs:
+     * By default, the request is kept active until one of the following occurs:
      * <ul>
+     *     <li>The system deems the request can no longer be honored, for example if the requested
+     *     state becomes unsupported.
+     *     <li>A call to {@link #cancelRequest(DeviceStateRequest)}.
      *     <li>Another processes submits a request succeeding this request in which case the request
      *     will be suspended until the interrupting request is canceled.
-     *     <li>The requested state has become unsupported.
-     *     <li>The process submitting the request dies.
      * </ul>
      * However, this behavior can be changed by setting flags on the {@link DeviceStateRequest}.
      *
      * @throws IllegalArgumentException if the requested state is unsupported.
-     * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE}
-     * permission is not held.
+     * @throws SecurityException if the caller is neither the current top-focused activity nor if
+     * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
      *
      * @see DeviceStateRequest
      */
-    @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
+    @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE,
+            conditional = true)
     public void requestState(@NonNull DeviceStateRequest request,
             @Nullable @CallbackExecutor Executor executor,
             @Nullable DeviceStateRequest.Callback callback) {
@@ -105,10 +106,11 @@
      * This method is noop if the {@code request} has not been submitted with a call to
      * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
      *
-     * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE}
-     * permission is not held.
+     * @throws SecurityException if the caller is neither the current top-focused activity nor if
+     * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
      */
-    @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
+    @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE,
+            conditional = true)
     public void cancelRequest(@NonNull DeviceStateRequest request) {
         mGlobal.cancelRequest(request);
     }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index e13a7b6..73961ff 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -864,7 +864,8 @@
         if (surface != null) {
             builder.setSurface(surface);
         }
-        return createVirtualDisplay(null /* projection */, builder.build(), callback, handler);
+        return createVirtualDisplay(null /* projection */, builder.build(), callback, handler,
+                null /* windowContext */);
     }
 
     // TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
@@ -882,15 +883,17 @@
         if (surface != null) {
             builder.setSurface(surface);
         }
-        return createVirtualDisplay(projection, builder.build(), callback, handler);
+        return createVirtualDisplay(projection, builder.build(), callback, handler,
+                null /* windowContext */);
     }
 
     /** @hide */
     public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
             @NonNull VirtualDisplayConfig virtualDisplayConfig,
-            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
+            @Nullable Context windowContext) {
         return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
-                handler);
+                handler, windowContext);
     }
 
     /**
@@ -940,6 +943,34 @@
     }
 
     /**
+     * Sets the brightness configuration for the specified display.
+     * If the specified display doesn't exist, then this will return and do nothing.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS)
+    public void setBrightnessConfigurationForDisplay(@NonNull BrightnessConfiguration c,
+            @NonNull String uniqueId) {
+        mGlobal.setBrightnessConfigurationForDisplay(c, uniqueId, mContext.getUserId(),
+                mContext.getPackageName());
+    }
+
+    /**
+     * Gets the brightness configuration for the specified display and default user.
+     * Returns the default configuration if unset or display is invalid.
+     *
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS)
+    public BrightnessConfiguration getBrightnessConfigurationForDisplay(
+            @NonNull String uniqueId) {
+        return mGlobal.getBrightnessConfigurationForDisplay(uniqueId, mContext.getUserId());
+    }
+
+    /**
      * Sets the global display brightness configuration for a specific user.
      *
      * Note this requires the INTERACT_ACROSS_USERS permission if setting the configuration for a
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index a9b95fc..1fec3c9f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -361,6 +361,11 @@
         for (int i = 0; i < numListeners; i++) {
             mask |= mDisplayListeners.get(i).mEventsMask;
         }
+        if (mDispatchNativeCallbacks) {
+            mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
+        }
         return mask;
     }
 
@@ -578,7 +583,7 @@
 
     public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
             @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
-            Handler handler) {
+            Handler handler, @Nullable Context windowContext) {
         VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
         IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
         int displayId;
@@ -604,7 +609,7 @@
             return null;
         }
         return new VirtualDisplay(this, display, callbackWrapper,
-                virtualDisplayConfig.getSurface());
+                virtualDisplayConfig.getSurface(), windowContext);
     }
 
     public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
@@ -705,6 +710,34 @@
     }
 
     /**
+     * Sets the brightness configuration for a given display.
+     *
+     * @hide
+     */
+    public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c,
+            String uniqueDisplayId, int userId, String packageName) {
+        try {
+            mDm.setBrightnessConfigurationForDisplay(c, uniqueDisplayId, userId, packageName);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the brightness configuration for a given display or null if one hasn't been set.
+     *
+     * @hide
+     */
+    public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId,
+            int userId) {
+        try {
+            return mDm.getBrightnessConfigurationForDisplay(uniqueDisplayId, userId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets the global brightness configuration for a given user or null if one hasn't been set.
      *
      * @hide
@@ -1047,12 +1080,17 @@
 
     private static native void nSignalNativeCallbacks(float refreshRate);
 
-    // Called from AChoreographer via JNI.
-    // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
-    private void registerNativeChoreographerForRefreshRateCallbacks() {
+    /**
+     * Called from AChoreographer via JNI.
+     * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
+     * Public for unit testing to be able to call this method.
+     */
+    @VisibleForTesting
+    public void registerNativeChoreographerForRefreshRateCallbacks() {
         synchronized (mLock) {
-            registerCallbackIfNeededLocked();
             mDispatchNativeCallbacks = true;
+            registerCallbackIfNeededLocked();
+            updateCallbackIfNeededLocked();
             DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
             if (display != null) {
                 // We need to tell AChoreographer instances the current refresh rate so that apps
@@ -1063,11 +1101,16 @@
         }
     }
 
-    // Called from AChoreographer via JNI.
-    // Unregisters AChoreographer from receiving refresh rate callbacks.
-    private void unregisterNativeChoreographerForRefreshRateCallbacks() {
+    /**
+     * Called from AChoreographer via JNI.
+     * Unregisters AChoreographer from receiving refresh rate callbacks.
+     * Public for unit testing to be able to call this method.
+     */
+    @VisibleForTesting
+    public void unregisterNativeChoreographerForRefreshRateCallbacks() {
         synchronized (mLock) {
             mDispatchNativeCallbacks = false;
+            updateCallbackIfNeededLocked();
         }
     }
 }
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/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 2303353..1162146 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -118,6 +118,16 @@
     void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId,
             String packageName);
 
+    // Sets the global brightness configuration for a given display. Requires
+    // CONFIGURE_DISPLAY_BRIGHTNESS.
+    void setBrightnessConfigurationForDisplay(in BrightnessConfiguration c, String uniqueDisplayId,
+            int userId, String packageName);
+
+    // Gets the brightness configuration for a given display. Requires
+    // CONFIGURE_DISPLAY_BRIGHTNESS.
+    BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId,
+            int userId);
+
     // Gets the global brightness configuration for a given user. Requires
     // CONFIGURE_DISPLAY_BRIGHTNESS, and INTERACT_ACROSS_USER if the user is not
     // the same as the calling user.
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index bf62c95..71cbd20 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -15,6 +15,8 @@
  */
 package android.hardware.display;
 
+import android.annotation.Nullable;
+import android.content.Context;
 import android.view.Display;
 import android.view.Surface;
 
@@ -36,13 +38,19 @@
     private final Display mDisplay;
     private IVirtualDisplayCallback mToken;
     private Surface mSurface;
+    /**
+     * Store the WindowContext in a field. If it is a local variable, and it is garbage collected
+     * during a MediaProjection session, the WindowContainer listener no longer exists.
+     */
+    @Nullable private final Context mWindowContext;
 
     VirtualDisplay(DisplayManagerGlobal global, Display display,
-            IVirtualDisplayCallback token, Surface surface) {
+            IVirtualDisplayCallback token, Surface surface, Context windowContext) {
         mGlobal = global;
         mDisplay = display;
         mToken = token;
         mSurface = surface;
+        mWindowContext = windowContext;
     }
 
     /**
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/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 3c3ba59..56f8142 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -58,7 +58,7 @@
 public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
 
     private static final String TAG = "FaceManager";
-    private static final boolean DEBUG = true;
+
     private static final int MSG_ENROLL_RESULT = 100;
     private static final int MSG_ACQUIRED = 101;
     private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -207,13 +207,9 @@
             throw new IllegalArgumentException("Must supply an authentication callback");
         }
 
-        if (cancel != null) {
-            if (cancel.isCanceled()) {
-                Slog.w(TAG, "authentication already canceled");
-                return;
-            } else {
-                cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
-            }
+        if (cancel != null && cancel.isCanceled()) {
+            Slog.w(TAG, "authentication already canceled");
+            return;
         }
 
         if (mService != null) {
@@ -223,17 +219,18 @@
                 mCryptoObject = crypto;
                 final long operationId = crypto != null ? crypto.getOpId() : 0;
                 Trace.beginSection("FaceManager#authenticate");
-                mService.authenticate(mToken, operationId, userId, mServiceReceiver,
-                        mContext.getOpPackageName(), isKeyguardBypassEnabled);
+                final long authId = mService.authenticate(mToken, operationId, userId,
+                        mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
+                if (cancel != null) {
+                    cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
+                }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Remote exception while authenticating: ", e);
-                if (callback != null) {
-                    // Though this may not be a hardware issue, it will cause apps to give up or
-                    // try again later.
-                    callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
-                            getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
-                                    0 /* vendorCode */));
-                }
+                // Though this may not be a hardware issue, it will cause apps to give up or
+                // try again later.
+                callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
+                        getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+                                0 /* vendorCode */));
             } finally {
                 Trace.endSection();
             }
@@ -255,14 +252,14 @@
         if (cancel.isCanceled()) {
             Slog.w(TAG, "Detection already cancelled");
             return;
-        } else {
-            cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
         }
 
         mFaceDetectionCallback = callback;
 
         try {
-            mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+            final long authId = mService.detectFace(
+                    mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+            cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId));
         } catch (RemoteException e) {
             Slog.w(TAG, "Remote exception when requesting finger detect", e);
         }
@@ -726,23 +723,23 @@
         }
     }
 
-    private void cancelAuthentication(CryptoObject cryptoObject) {
+    private void cancelAuthentication(long requestId) {
         if (mService != null) {
             try {
-                mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+                mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
     }
 
-    private void cancelFaceDetect() {
+    private void cancelFaceDetect(long requestId) {
         if (mService == null) {
             return;
         }
 
         try {
-            mService.cancelFaceDetect(mToken, mContext.getOpPackageName());
+            mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -790,8 +787,13 @@
                 }
             }
         }
+
+        // This is used as a last resort in case a vendor string is missing
+        // It should not happen for anything other than FACE_ERROR_VENDOR, but
+        // warn and use the default if all else fails.
         Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
-        return "";
+        return context.getString(
+                com.android.internal.R.string.face_error_vendor_unknown);
     }
 
     /**
@@ -1105,22 +1107,30 @@
     }
 
     private class OnAuthenticationCancelListener implements OnCancelListener {
-        private final CryptoObject mCrypto;
+        private final long mAuthRequestId;
 
-        OnAuthenticationCancelListener(CryptoObject crypto) {
-            mCrypto = crypto;
+        OnAuthenticationCancelListener(long id) {
+            mAuthRequestId = id;
         }
 
         @Override
         public void onCancel() {
-            cancelAuthentication(mCrypto);
+            Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId);
+            cancelAuthentication(mAuthRequestId);
         }
     }
 
     private class OnFaceDetectionCancelListener implements OnCancelListener {
+        private final long mAuthRequestId;
+
+        OnFaceDetectionCancelListener(long id) {
+            mAuthRequestId = id;
+        }
+
         @Override
         public void onCancel() {
-            cancelFaceDetect();
+            Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId);
+            cancelFaceDetect(mAuthRequestId);
         }
     }
 
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index db02a0ef..e919824 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -44,34 +44,36 @@
     // Retrieve static sensor properties for the specified sensor
     FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
 
-    // Authenticate the given sessionId with a face
-    void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
+    // Authenticate with a face. A requestId is returned that can be used to cancel this operation.
+    long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
             String opPackageName, boolean isKeyguardBypassEnabled);
 
     // Uses the face hardware to detect for the presence of a face, without giving details
-    // about accept/reject/lockout.
-    void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
+    // about accept/reject/lockout. A requestId is returned that can be used to cancel this
+    // operation.
+    long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
 
     // This method prepares the service to start authenticating, but doesn't start authentication.
     // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
     // called from BiometricService. The additional uid, pid, userId arguments should be determined
     // by BiometricService. To start authentication after the clients are ready, use
     // startPreparedClient().
-    void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
-            int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie, boolean allowBackgroundAuthentication);
+    void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token,
+            long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
+            String opPackageName, long requestId, int cookie,
+            boolean allowBackgroundAuthentication);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int sensorId, int cookie);
 
-    // Cancel authentication for the given sessionId
-    void cancelAuthentication(IBinder token, String opPackageName);
+    // Cancel authentication for the given requestId.
+    void cancelAuthentication(IBinder token, String opPackageName, long requestId);
 
-    // Cancel face detection
-    void cancelFaceDetect(IBinder token, String opPackageName);
+    // Cancel face detection for the given requestId.
+    void cancelFaceDetect(IBinder token, String opPackageName, long requestId);
 
     // Same as above, with extra arguments.
-    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
+    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
 
     // Start face enrollment
     void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index dc1a50f..7c42dc0 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -189,22 +189,30 @@
     }
 
     private class OnAuthenticationCancelListener implements OnCancelListener {
-        private android.hardware.biometrics.CryptoObject mCrypto;
+        private final long mAuthRequestId;
 
-        public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
-            mCrypto = crypto;
+        OnAuthenticationCancelListener(long id) {
+            mAuthRequestId = id;
         }
 
         @Override
         public void onCancel() {
-            cancelAuthentication(mCrypto);
+            Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
+            cancelAuthentication(mAuthRequestId);
         }
     }
 
     private class OnFingerprintDetectionCancelListener implements OnCancelListener {
+        private final long mAuthRequestId;
+
+        OnFingerprintDetectionCancelListener(long id) {
+            mAuthRequestId = id;
+        }
+
         @Override
         public void onCancel() {
-            cancelFingerprintDetect();
+            Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId);
+            cancelFingerprintDetect(mAuthRequestId);
         }
     }
 
@@ -552,13 +560,9 @@
             throw new IllegalArgumentException("Must supply an authentication callback");
         }
 
-        if (cancel != null) {
-            if (cancel.isCanceled()) {
-                Slog.w(TAG, "authentication already canceled");
-                return;
-            } else {
-                cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
-            }
+        if (cancel != null && cancel.isCanceled()) {
+            Slog.w(TAG, "authentication already canceled");
+            return;
         }
 
         if (mService != null) {
@@ -567,8 +571,11 @@
                 mAuthenticationCallback = callback;
                 mCryptoObject = crypto;
                 final long operationId = crypto != null ? crypto.getOpId() : 0;
-                mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver,
-                        mContext.getOpPackageName());
+                final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
+                        mServiceReceiver, mContext.getOpPackageName());
+                if (cancel != null) {
+                    cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
+                }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Remote exception while authenticating: ", e);
                 // Though this may not be a hardware issue, it will cause apps to give up or try
@@ -595,15 +602,14 @@
         if (cancel.isCanceled()) {
             Slog.w(TAG, "Detection already cancelled");
             return;
-        } else {
-            cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
         }
 
         mFingerprintDetectionCallback = callback;
 
         try {
-            mService.detectFingerprint(mToken, userId, mServiceReceiver,
+            final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
                     mContext.getOpPackageName());
+            cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
         } catch (RemoteException e) {
             Slog.w(TAG, "Remote exception when requesting finger detect", e);
         }
@@ -1320,21 +1326,21 @@
         }
     }
 
-    private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) {
+    private void cancelAuthentication(long requestId) {
         if (mService != null) try {
-            mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+            mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
-    private void cancelFingerprintDetect() {
+    private void cancelFingerprintDetect(long requestId) {
         if (mService == null) {
             return;
         }
 
         try {
-            mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName());
+            mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1386,8 +1392,13 @@
                 }
             }
         }
+
+        // This is used as a last resort in case a vendor string is missing
+        // It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but
+        // warn and use the default if all else fails.
         Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
-        return null;
+        return context.getString(
+                com.android.internal.R.string.fingerprint_error_vendor_unknown);
     }
 
     /**
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3979afe..4774827 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -48,15 +48,16 @@
     // Retrieve static sensor properties for the specified sensor
     FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
 
-    // Authenticate the given sessionId with a fingerprint. This is protected by
-    // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
-    // through FingerprintManager now.
-    void authenticate(IBinder token, long operationId, int sensorId, int userId,
+    // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC
+    // permission. This is effectively deprecated, since it only comes through FingerprintManager
+    // now. A requestId is returned that can be used to cancel this operation.
+    long authenticate(IBinder token, long operationId, int sensorId, int userId,
             IFingerprintServiceReceiver receiver, String opPackageName);
 
     // Uses the fingerprint hardware to detect for the presence of a finger, without giving details
-    // about accept/reject/lockout.
-    void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
+    // about accept/reject/lockout. A requestId is returned that can be used to cancel this
+    // operation.
+    long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
             String opPackageName);
 
     // This method prepares the service to start authenticating, but doesn't start authentication.
@@ -65,21 +66,21 @@
     // by BiometricService. To start authentication after the clients are ready, use
     // startPreparedClient().
     void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
-            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
-            boolean allowBackgroundAuthentication);
+            IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
+            int cookie, boolean allowBackgroundAuthentication);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int sensorId, int cookie);
 
-    // Cancel authentication for the given sessionId
-    void cancelAuthentication(IBinder token, String opPackageName);
+    // Cancel authentication for the given requestId.
+    void cancelAuthentication(IBinder token, String opPackageName, long requestId);
 
-    // Cancel finger detection
-    void cancelFingerprintDetect(IBinder token, String opPackageName);
+    // Cancel finger detection for the given requestId.
+    void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId);
 
     // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
     // an additional uid, pid, userid.
-    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
+    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
 
     // Start fingerprint enrollment
     void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
index cbfbe39..79846cd 100644
--- a/core/java/android/hardware/hdmi/HdmiSwitchClient.java
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -165,7 +165,9 @@
      *     there is none.
      *
      * @hide
+     * @deprecated Please use {@link HdmiControlManager#getConnectedDevices()} instead.
      */
+    @Deprecated
     public List<HdmiDeviceInfo> getDeviceList() {
         try {
             return mService.getDeviceList();
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index f33a137..e1ed3ea 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -158,7 +158,9 @@
      *
      * @return list of {@link HdmiDeviceInfo} for connected CEC devices.
      *         Empty list is returned if there is none.
+     * @deprecated Please use {@link HdmiControlManager#getConnectedDevices()} instead.
      */
+    @Deprecated
     public List<HdmiDeviceInfo> getDeviceList() {
         try {
             return mService.getDeviceList();
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index 429f1f3..7bf234b 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -80,14 +80,14 @@
     void setConfigFlag(int flag, boolean value);
 
     /**
-     * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
-     * @return Vendor-specific key-value pairs, must be Map<String, String>
+     * @param parameters Vendor-specific key-value pairs
+     * @return Vendor-specific key-value pairs
      */
-    Map setParameters(in Map parameters);
+    Map<String, String> setParameters(in Map<String, String> parameters);
 
     /**
      * @param keys Parameter keys to fetch
-     * @return Vendor-specific key-value pairs, must be Map<String, String>
+     * @return Vendor-specific key-value pairs
      */
-    Map getParameters(in List<String> keys);
+    Map<String, String> getParameters(in List<String> keys);
 }
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index b32daa5..f98947b 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -36,7 +36,7 @@
     void onProgramListUpdated(in ProgramList.Chunk chunk);
 
     /**
-     * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
+     * @param parameters Vendor-specific key-value pairs
      */
-    void onParametersUpdated(in Map parameters);
+    void onParametersUpdated(in Map<String, String> parameters);
 }
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index beff0f7..e3f7001 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -220,7 +220,7 @@
     }
 
     @Override
-    public void onParametersUpdated(Map parameters) {
+    public void onParametersUpdated(Map<String, String> parameters) {
         mHandler.post(() -> mCallback.onParametersUpdated(parameters));
     }
 }
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index ad0dc09..35a974b 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.media.AudioFormat;
+import android.media.audio.common.AidlConversion;
 import android.media.audio.common.AudioConfig;
 import android.media.soundtrigger.AudioCapabilities;
 import android.media.soundtrigger.ConfidenceLevel;
@@ -197,7 +198,8 @@
             int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
-        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig);
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
+                aidlEvent.audioConfig, true /*isInput*/);
         return new SoundTrigger.GenericRecognitionEvent(
                 aidlEvent.status,
                 modelHandle, aidlEvent.captureAvailable, captureSession,
@@ -215,7 +217,8 @@
         }
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
-        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig);
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
+                aidlEvent.common.audioConfig, true /*isInput*/);
         return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
                 aidlEvent.common.captureAvailable,
                 captureSession, aidlEvent.common.captureDelayMs,
@@ -224,107 +227,15 @@
                 apiExtras);
     }
 
-    public static AudioFormat aidl2apiAudioFormat(AudioConfig audioConfig) {
-        AudioFormat.Builder apiBuilder = new AudioFormat.Builder();
-        apiBuilder.setSampleRate(audioConfig.sampleRateHz);
-        apiBuilder.setChannelMask(aidl2apiChannelInMask(audioConfig.channelMask));
-        apiBuilder.setEncoding(aidl2apiEncoding(audioConfig.format));
-        return apiBuilder.build();
-    }
-
-    // Same as above, but in case of a null input returns a non-null valid output.
-    public static AudioFormat aidl2apiAudioFormatWithDefault(@Nullable AudioConfig audioConfig) {
+    // In case of a null input returns a non-null valid output.
+    public static AudioFormat aidl2apiAudioFormatWithDefault(
+            @Nullable AudioConfig audioConfig, boolean isInput) {
         if (audioConfig != null) {
-            return aidl2apiAudioFormat(audioConfig);
+            return AidlConversion.aidl2api_AudioConfig_AudioFormat(audioConfig, isInput);
         }
         return new AudioFormat.Builder().build();
     }
 
-    public static int aidl2apiEncoding(int aidlFormat) {
-        switch (aidlFormat) {
-            case android.media.audio.common.AudioFormat.PCM
-                    | android.media.audio.common.AudioFormat.PCM_SUB_16_BIT:
-                return AudioFormat.ENCODING_PCM_16BIT;
-
-            case android.media.audio.common.AudioFormat.PCM
-                    | android.media.audio.common.AudioFormat.PCM_SUB_8_BIT:
-                return AudioFormat.ENCODING_PCM_8BIT;
-
-            case android.media.audio.common.AudioFormat.PCM
-                    | android.media.audio.common.AudioFormat.PCM_SUB_FLOAT:
-            case android.media.audio.common.AudioFormat.PCM
-                    | android.media.audio.common.AudioFormat.PCM_SUB_8_24_BIT:
-            case android.media.audio.common.AudioFormat.PCM
-                    | android.media.audio.common.AudioFormat.PCM_SUB_24_BIT_PACKED:
-            case android.media.audio.common.AudioFormat.PCM
-                    | android.media.audio.common.AudioFormat.PCM_SUB_32_BIT:
-                return AudioFormat.ENCODING_PCM_FLOAT;
-
-            case android.media.audio.common.AudioFormat.AC3:
-                return AudioFormat.ENCODING_AC3;
-
-            case android.media.audio.common.AudioFormat.E_AC3:
-                return AudioFormat.ENCODING_E_AC3;
-
-            case android.media.audio.common.AudioFormat.DTS:
-                return AudioFormat.ENCODING_DTS;
-
-            case android.media.audio.common.AudioFormat.DTS_HD:
-                return AudioFormat.ENCODING_DTS_HD;
-
-            case android.media.audio.common.AudioFormat.MP3:
-                return AudioFormat.ENCODING_MP3;
-
-            case android.media.audio.common.AudioFormat.AAC
-                    | android.media.audio.common.AudioFormat.AAC_SUB_LC:
-                return AudioFormat.ENCODING_AAC_LC;
-
-            case android.media.audio.common.AudioFormat.AAC
-                    | android.media.audio.common.AudioFormat.AAC_SUB_HE_V1:
-                return AudioFormat.ENCODING_AAC_HE_V1;
-
-            case android.media.audio.common.AudioFormat.AAC
-                    | android.media.audio.common.AudioFormat.AAC_SUB_HE_V2:
-                return AudioFormat.ENCODING_AAC_HE_V2;
-
-            case android.media.audio.common.AudioFormat.IEC61937:
-                return AudioFormat.ENCODING_IEC61937;
-
-            case android.media.audio.common.AudioFormat.DOLBY_TRUEHD:
-                return AudioFormat.ENCODING_DOLBY_TRUEHD;
-
-            case android.media.audio.common.AudioFormat.AAC
-                    | android.media.audio.common.AudioFormat.AAC_SUB_ELD:
-                return AudioFormat.ENCODING_AAC_ELD;
-
-            case android.media.audio.common.AudioFormat.AAC
-                    | android.media.audio.common.AudioFormat.AAC_SUB_XHE:
-                return AudioFormat.ENCODING_AAC_XHE;
-
-            case android.media.audio.common.AudioFormat.AC4:
-                return AudioFormat.ENCODING_AC4;
-
-            case android.media.audio.common.AudioFormat.E_AC3
-                    | android.media.audio.common.AudioFormat.E_AC3_SUB_JOC:
-                return AudioFormat.ENCODING_E_AC3_JOC;
-
-            case android.media.audio.common.AudioFormat.MAT:
-            case android.media.audio.common.AudioFormat.MAT
-                    | android.media.audio.common.AudioFormat.MAT_SUB_1_0:
-            case android.media.audio.common.AudioFormat.MAT
-                    | android.media.audio.common.AudioFormat.MAT_SUB_2_0:
-            case android.media.audio.common.AudioFormat.MAT
-                    | android.media.audio.common.AudioFormat.MAT_SUB_2_1:
-                return AudioFormat.ENCODING_DOLBY_MAT;
-
-            case android.media.audio.common.AudioFormat.DEFAULT:
-                return AudioFormat.ENCODING_DEFAULT;
-
-            default:
-                return AudioFormat.ENCODING_INVALID;
-        }
-    }
-
     public static int api2aidlModelParameter(int apiParam) {
         switch (apiParam) {
             case ModelParams.THRESHOLD_FACTOR:
@@ -334,12 +245,6 @@
         }
     }
 
-    public static int aidl2apiChannelInMask(int aidlMask) {
-        // We're assuming AudioFormat.CHANNEL_IN_* constants are kept in sync with
-        // android.media.audio.common.AudioChannelMask.
-        return aidlMask;
-    }
-
     public static SoundTrigger.ModelParamRange aidl2apiModelParameterRange(
             @Nullable ModelParameterRange aidlRange) {
         if (aidlRange == null) {
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 9db41c4..a6e77023 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -294,7 +294,7 @@
     @Override
     @Nullable
     public final Bundle getWindowContextOptions() {
-        return null;
+        return super.getWindowContextOptions();
     }
 
     /** @hide */
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index dadea67..4255d88 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1731,12 +1731,12 @@
         if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
             return false;
         }
-        if ((mInputEditorInfo != null
-                && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0)
+        if (mInputEditorInfo != null
+                && ((mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0
                 // If app window has portrait orientation, regardless of what display orientation
                 // is, IME shouldn't use fullscreen-mode.
                 || (mInputEditorInfo.internalImeOptions
-                        & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) {
+                        & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0)) {
             return false;
         }
         return true;
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index ec5bcf1..464b421 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -34,7 +34,7 @@
 import android.view.inputmethod.SurroundingText;
 
 import com.android.internal.inputmethod.CancellationGroup;
-import com.android.internal.inputmethod.Completable;
+import com.android.internal.inputmethod.CompletableFutureUtil;
 import com.android.internal.inputmethod.IInputContextInvoker;
 import com.android.internal.inputmethod.ImeTracing;
 import com.android.internal.inputmethod.InputConnectionProtoDumper;
@@ -42,6 +42,7 @@
 import com.android.internal.view.IInputMethod;
 
 import java.lang.ref.WeakReference;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * Takes care of remote method invocations of {@link InputConnection} in the IME side.
@@ -96,8 +97,8 @@
             return null;
         }
 
-        final Completable.CharSequence value = mInvoker.getTextAfterCursor(length, flags);
-        final CharSequence result = Completable.getResultOrNull(
+        final CompletableFuture<CharSequence> value = mInvoker.getTextAfterCursor(length, flags);
+        final CharSequence result = CompletableFutureUtil.getResultOrNull(
                 value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
 
         final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -120,8 +121,8 @@
             return null;
         }
 
-        final Completable.CharSequence value = mInvoker.getTextBeforeCursor(length, flags);
-        final CharSequence result = Completable.getResultOrNull(
+        final CompletableFuture<CharSequence> value = mInvoker.getTextBeforeCursor(length, flags);
+        final CharSequence result = CompletableFutureUtil.getResultOrNull(
                 value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
 
         final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -144,8 +145,8 @@
             // This method is not implemented.
             return null;
         }
-        final Completable.CharSequence value = mInvoker.getSelectedText(flags);
-        final CharSequence result = Completable.getResultOrNull(
+        final CompletableFuture<CharSequence> value = mInvoker.getSelectedText(flags);
+        final CharSequence result = CompletableFutureUtil.getResultOrNull(
                 value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
 
         final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -181,9 +182,9 @@
             // This method is not implemented.
             return null;
         }
-        final Completable.SurroundingText value = mInvoker.getSurroundingText(beforeLength,
+        final CompletableFuture<SurroundingText> value = mInvoker.getSurroundingText(beforeLength,
                 afterLength, flags);
-        final SurroundingText result = Completable.getResultOrNull(
+        final SurroundingText result = CompletableFutureUtil.getResultOrNull(
                 value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
 
         final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -202,8 +203,8 @@
             return 0;
         }
 
-        final Completable.Int value = mInvoker.getCursorCapsMode(reqModes);
-        final int result = Completable.getResultOrZero(
+        final CompletableFuture<Integer> value = mInvoker.getCursorCapsMode(reqModes);
+        final int result = CompletableFutureUtil.getResultOrZero(
                 value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
 
         final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -222,8 +223,8 @@
             return null;
         }
 
-        final Completable.ExtractedText value = mInvoker.getExtractedText(request, flags);
-        final ExtractedText result = Completable.getResultOrNull(
+        final CompletableFuture<ExtractedText> value = mInvoker.getExtractedText(request, flags);
+        final ExtractedText result = CompletableFutureUtil.getResultOrNull(
                 value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
 
         final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -371,8 +372,8 @@
             // This method is not implemented.
             return false;
         }
-        final Completable.Boolean value = mInvoker.requestCursorUpdates(cursorUpdateMode);
-        return Completable.getResultOrFalse(value, TAG, "requestCursorUpdates()",
+        final CompletableFuture<Boolean> value = mInvoker.requestCursorUpdates(cursorUpdateMode);
+        return CompletableFutureUtil.getResultOrFalse(value, TAG, "requestCursorUpdates()",
                 mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
@@ -407,8 +408,9 @@
             inputMethodService.exposeContent(inputContentInfo, this);
         }
 
-        final Completable.Boolean value = mInvoker.commitContent(inputContentInfo, flags, opts);
-        return Completable.getResultOrFalse(
+        final CompletableFuture<Boolean> value =
+                mInvoker.commitContent(inputContentInfo, flags, opts);
+        return CompletableFutureUtil.getResultOrFalse(
                 value, TAG, "commitContent()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
diff --git a/core/java/android/net/PacProxyManager.java b/core/java/android/net/PacProxyManager.java
index 8f7ad8c..da79634 100644
--- a/core/java/android/net/PacProxyManager.java
+++ b/core/java/android/net/PacProxyManager.java
@@ -94,7 +94,7 @@
     }
 
     /**
-     * Updates the PAC Proxy Installer with current Proxy information.
+     * Updates the PAC Proxy Service with current Proxy information.
      */
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_STACK,
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 1692921f..6da02f5 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -31,6 +31,7 @@
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * A mapping from String keys to values of various types. In most cases, you
@@ -38,7 +39,8 @@
  * {@link PersistableBundle} subclass.
  */
 public class BaseBundle {
-    private static final String TAG = "Bundle";
+    /** @hide */
+    protected static final String TAG = "Bundle";
     static final boolean DEBUG = false;
 
     // Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
@@ -95,7 +97,7 @@
     Parcel mParcelledData = null;
 
     /**
-     * Whether {@link #mParcelledData} was generated by native coed or not.
+     * Whether {@link #mParcelledData} was generated by native code or not.
      */
     private boolean mParcelledByNative;
 
@@ -198,7 +200,7 @@
         if (size == 0) {
             return null;
         }
-        Object o = mMap.valueAt(0);
+        Object o = getValueAt(0);
         try {
             return (String) o;
         } catch (ClassCastException e) {
@@ -229,7 +231,12 @@
      * using the currently assigned class loader.
      */
     @UnsupportedAppUsage
-    /* package */ void unparcel() {
+    final void unparcel() {
+        unparcel(/* itemwise */ false);
+    }
+
+    /** Deserializes the underlying data and each item if {@code itemwise} is true. */
+    final void unparcel(boolean itemwise) {
         synchronized (this) {
             final Parcel source = mParcelledData;
             if (source != null) {
@@ -241,9 +248,42 @@
                             + ": no parcelled data");
                 }
             }
+            if (itemwise) {
+                for (int i = 0, n = mMap.size(); i < n; i++) {
+                    // Triggers deserialization of i-th item, if needed
+                    getValueAt(i);
+                }
+            }
         }
     }
 
+    /**
+     * Returns the value for key {@code key}.
+     *
+     * @hide
+     */
+    final Object getValue(String key) {
+        int i = mMap.indexOfKey(key);
+        return (i >= 0) ? getValueAt(i) : null;
+    }
+
+    /**
+     * Returns the value for a certain position in the array map.
+     *
+     * @hide
+     */
+    final Object getValueAt(int i) {
+        Object object = mMap.valueAt(i);
+        if (object instanceof Supplier<?>) {
+            Supplier<?> supplier = (Supplier<?>) object;
+            synchronized (this) {
+                object = supplier.get();
+            }
+            mMap.setValueAt(i, object);
+        }
+        return object;
+    }
+
     private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
             boolean parcelledByNative) {
         if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
@@ -282,15 +322,8 @@
             map.ensureCapacity(count);
         }
         try {
-            if (parcelledByNative) {
-                // If it was parcelled by native code, then the array map keys aren't sorted
-                // by their hash codes, so use the safe (slow) one.
-                parcelledData.readArrayMapSafelyInternal(map, count, mClassLoader);
-            } else {
-                // If parcelled by Java, we know the contents are sorted properly,
-                // so we can use ArrayMap.append().
-                parcelledData.readArrayMapInternal(map, count, mClassLoader);
-            }
+            recycleParcel &= parcelledData.readArrayMap(map, count, !parcelledByNative,
+                    /* lazy */ true, mClassLoader);
         } catch (BadParcelableException e) {
             if (sShouldDefuse) {
                 Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
@@ -342,7 +375,7 @@
 
     /** @hide */
     ArrayMap<String, Object> getMap() {
-        unparcel();
+        unparcel(/* itemwise */ true);
         return mMap;
     }
 
@@ -400,7 +433,12 @@
     }
 
     /**
-     * @hide This kind-of does an equality comparison.  Kind-of.
+     * Performs a loose equality check, which means there can be false negatives but if the method
+     * returns true than both objects are guaranteed to be equal.
+     *
+     * The point is that this method is a light-weight check in performance terms.
+     *
+     * @hide
      */
     public boolean kindofEquals(BaseBundle other) {
         if (other == null) {
@@ -415,6 +453,12 @@
         } else if (isParcelled()) {
             return mParcelledData.compareData(other.mParcelledData) == 0;
         } else {
+            // Following semantic above of failing in case we get a serialized value vs a
+            // deserialized one, we'll compare the map. If a certain element hasn't been
+            // deserialized yet, it's a Supplier (or more specifically a LazyValue, but let's
+            // pretend we don't know that here :P), we'll use that element's equality comparison as
+            // map naturally does. That will takes care of comparing the payload if needed (see
+            // Parcel.readLazyValue() for details).
             return mMap.equals(other.mMap);
         }
     }
@@ -453,7 +497,7 @@
                     final int N = fromMap.size();
                     mMap = new ArrayMap<>(N);
                     for (int i = 0; i < N; i++) {
-                        mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
+                        mMap.append(fromMap.keyAt(i), deepCopyValue(from.getValueAt(i)));
                     }
                 }
             } else {
@@ -526,7 +570,7 @@
     @Nullable
     public Object get(String key) {
         unparcel();
-        return mMap.get(key);
+        return getValue(key);
     }
 
     /**
@@ -1001,7 +1045,7 @@
      */
     char getChar(String key, char defaultValue) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return defaultValue;
         }
@@ -1266,7 +1310,7 @@
     @Nullable
     Serializable getSerializable(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1289,7 +1333,7 @@
     @Nullable
     ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1312,7 +1356,7 @@
     @Nullable
     ArrayList<String> getStringArrayList(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1335,7 +1379,7 @@
     @Nullable
     ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1404,7 +1448,7 @@
     @Nullable
     short[] getShortArray(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1427,7 +1471,7 @@
     @Nullable
     char[] getCharArray(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1496,7 +1540,7 @@
     @Nullable
     float[] getFloatArray(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1585,7 +1629,7 @@
     void writeToParcelInner(Parcel parcel, int flags) {
         // If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first.
         if (parcel.hasReadWriteHelper()) {
-            unparcel();
+            unparcel(/* itemwise */ true);
         }
         // Keep implementation in sync with writeToParcel() in
         // frameworks/native/libs/binder/PersistableBundle.cpp.
@@ -1660,10 +1704,13 @@
         }
 
         if (parcel.hasReadWriteHelper()) {
-            // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just
-            // unparcel right away.
+            // If the parcel has a read-write helper, it's better to deserialize immediately
+            // otherwise the helper would have to either maintain valid state long after the bundle
+            // had been constructed with parcel or to make sure they trigger deserialization of the
+            // bundle immediately; neither of which is obvious.
             synchronized (this) {
                 initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle);
+                unparcel(/* itemwise */ true);
             }
             return;
         }
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index b128f68..a7b67ef 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -271,6 +271,16 @@
     }
 
     /**
+     * Returns the names of custom power components in order, so the first name in the array
+     * corresponds to the custom componentId
+     * {@link BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID}.
+     */
+    @NonNull
+    public String[] getCustomPowerComponentNames() {
+        return mCustomPowerComponentNames;
+    }
+
+    /**
      * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
      */
     @NonNull
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 102f525..b6163f1 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -331,47 +331,9 @@
                 // It's been unparcelled, so we need to walk the map
                 for (int i=mMap.size()-1; i>=0; i--) {
                     Object obj = mMap.valueAt(i);
-                    if (obj instanceof Parcelable) {
-                        if ((((Parcelable)obj).describeContents()
-                                & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
-                            fdFound = true;
-                            break;
-                        }
-                    } else if (obj instanceof Parcelable[]) {
-                        Parcelable[] array = (Parcelable[]) obj;
-                        for (int n = array.length - 1; n >= 0; n--) {
-                            Parcelable p = array[n];
-                            if (p != null && ((p.describeContents()
-                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
-                                fdFound = true;
-                                break;
-                            }
-                        }
-                    } else if (obj instanceof SparseArray) {
-                        SparseArray<? extends Parcelable> array =
-                                (SparseArray<? extends Parcelable>) obj;
-                        for (int n = array.size() - 1; n >= 0; n--) {
-                            Parcelable p = array.valueAt(n);
-                            if (p != null && (p.describeContents()
-                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
-                                fdFound = true;
-                                break;
-                            }
-                        }
-                    } else if (obj instanceof ArrayList) {
-                        ArrayList array = (ArrayList) obj;
-                        // an ArrayList here might contain either Strings or
-                        // Parcelables; only look inside for Parcelables
-                        if (!array.isEmpty() && (array.get(0) instanceof Parcelable)) {
-                            for (int n = array.size() - 1; n >= 0; n--) {
-                                Parcelable p = (Parcelable) array.get(n);
-                                if (p != null && ((p.describeContents()
-                                        & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
-                                    fdFound = true;
-                                    break;
-                                }
-                            }
-                        }
+                    if (Parcel.hasFileDescriptors(obj)) {
+                        fdFound = true;
+                        break;
                     }
                 }
             }
@@ -392,7 +354,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public Bundle filterValues() {
-        unparcel();
+        unparcel(/* itemwise */ true);
         Bundle bundle = this;
         if (mMap != null) {
             ArrayMap<String, Object> map = mMap;
@@ -973,7 +935,7 @@
     @Nullable
     public Bundle getBundle(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1000,7 +962,7 @@
     @Nullable
     public <T extends Parcelable> T getParcelable(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1027,7 +989,7 @@
     @Nullable
     public Parcelable[] getParcelableArray(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1054,7 +1016,7 @@
     @Nullable
     public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1078,7 +1040,7 @@
     @Nullable
     public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(@Nullable String key) {
         unparcel();
-        Object o = mMap.get(key);
+        Object o = getValue(key);
         if (o == null) {
             return null;
         }
@@ -1301,7 +1263,7 @@
     public void writeToParcel(Parcel parcel, int flags) {
         final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
         try {
-            super.writeToParcelInner(parcel, flags);
+            writeToParcelInner(parcel, flags);
         } finally {
             parcel.restoreAllowFds(oldAllowFds);
         }
@@ -1313,7 +1275,7 @@
      * @param parcel The parcel to overwrite this bundle from.
      */
     public void readFromParcel(Parcel parcel) {
-        super.readFromParcelInner(parcel);
+        readFromParcelInner(parcel);
         mFlags = FLAG_ALLOW_FDS;
         maybePrefillHasFds();
     }
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/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index 7fd02116..0686dd6 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -42,25 +42,38 @@
     // boundaries.
     @NonNull
     private IBinder mToken;
-
     public ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
             @NonNull IExternalVibrationController controller) {
+        this(uid, pkg, attrs, controller, new Binder());
+    }
+
+    private ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
+            @NonNull IExternalVibrationController controller, @NonNull IBinder token) {
         mUid = uid;
         mPkg = Preconditions.checkNotNull(pkg);
         mAttrs = Preconditions.checkNotNull(attrs);
         mController = Preconditions.checkNotNull(controller);
-        mToken = new Binder();
+        mToken = Preconditions.checkNotNull(token);
+
+        // IExternalVibrationController is a hidden AIDL interface with implementation provided by
+        // the audio framework to allow mute/unmute control over the external vibration.
+        //
+        // Transactions are locked in audioflinger, and should be blocking to avoid racing
+        // conditions on multiple audio playback.
+        //
+        // They can also be triggered before starting a new external vibration in
+        // IExternalVibratorService, as the ongoing external vibration needs to be muted before the
+        // new one can start, which also requires blocking calls to mute.
+        Binder.allowBlocking(mController.asBinder());
     }
 
     private ExternalVibration(Parcel in) {
-        mUid = in.readInt();
-        mPkg = in.readString();
-        mAttrs = readAudioAttributes(in);
-        mController = IExternalVibrationController.Stub.asInterface(in.readStrongBinder());
-        mToken = in.readStrongBinder();
+        this(in.readInt(), in.readString(), readAudioAttributes(in),
+                IExternalVibrationController.Stub.asInterface(in.readStrongBinder()),
+                in.readStrongBinder());
     }
 
-    private AudioAttributes readAudioAttributes(Parcel in) {
+    private static AudioAttributes readAudioAttributes(Parcel in) {
         int usage = in.readInt();
         int contentType = in.readInt();
         int capturePreset = in.readInt();
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1bc6495..edfcb3d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1470,7 +1470,7 @@
         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/Parcel.java b/core/java/android/os/Parcel.java
index e06e7b6..f132ac5 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -26,6 +26,7 @@
 import android.util.ArraySet;
 import android.util.ExceptionUtils;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.Size;
 import android.util.SizeF;
 import android.util.Slog;
@@ -56,7 +57,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * Container for a message (data and object references) that can
@@ -679,6 +682,66 @@
     }
 
     /**
+     * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)}
+     * has file descriptors.
+     *
+     * <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method
+     * for that.
+     *
+     * @throws IllegalArgumentException if you provide any object not supported by above methods.
+     *         Most notably, if you pass {@link Parcel}, this method will throw, for that check
+     *         {@link Parcel#hasFileDescriptors()}
+     *
+     * @hide
+     */
+    public static boolean hasFileDescriptors(Object value) {
+        if (value instanceof LazyValue) {
+            return ((LazyValue) value).hasFileDescriptors();
+        } else if (value instanceof Parcelable) {
+            if ((((Parcelable) value).describeContents()
+                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+                return true;
+            }
+        } else if (value instanceof Parcelable[]) {
+            Parcelable[] array = (Parcelable[]) value;
+            for (int n = array.length - 1; n >= 0; n--) {
+                Parcelable p = array[n];
+                if (p != null && ((p.describeContents()
+                        & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+                    return true;
+                }
+            }
+        } else if (value instanceof SparseArray<?>) {
+            SparseArray<?> array = (SparseArray<?>) value;
+            for (int n = array.size() - 1; n >= 0; n--) {
+                Object object = array.valueAt(n);
+                if (object instanceof Parcelable) {
+                    Parcelable p = (Parcelable) object;
+                    if (p != null && (p.describeContents()
+                            & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+                        return true;
+                    }
+                }
+            }
+        } else if (value instanceof ArrayList<?>) {
+            ArrayList<?> array = (ArrayList<?>) value;
+            for (int n = array.size() - 1; n >= 0; n--) {
+                Object object = array.get(n);
+                if (object instanceof Parcelable) {
+                    Parcelable p = (Parcelable) object;
+                    if (p != null && ((p.describeContents()
+                            & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+                        return true;
+                    }
+                }
+            }
+        } else {
+            getValueType(value); // Will throw if value is not supported
+        }
+        return false;
+    }
+
+    /**
      * Store or read an IBinder interface token in the parcel at the current
      * {@link #dataPosition}. This is used to validate that the marshalled
      * transaction is intended for the target interface. This is typically written
@@ -1832,108 +1895,206 @@
      * should be used).</p>
      */
     public final void writeValue(@Nullable Object v) {
+        if (v instanceof LazyValue) {
+            LazyValue value = (LazyValue) v;
+            value.writeToParcel(this);
+            return;
+        }
+        int type = getValueType(v);
+        writeInt(type);
+        if (isLengthPrefixed(type)) {
+            // Length
+            int length = dataPosition();
+            writeInt(-1); // Placeholder
+            // Object
+            int start = dataPosition();
+            writeValue(type, v);
+            int end = dataPosition();
+            // Backpatch length
+            setDataPosition(length);
+            writeInt(end - start);
+            setDataPosition(end);
+        } else {
+            writeValue(type, v);
+        }
+    }
+
+    /** @hide */
+    public static int getValueType(@Nullable Object v) {
         if (v == null) {
-            writeInt(VAL_NULL);
+            return VAL_NULL;
         } else if (v instanceof String) {
-            writeInt(VAL_STRING);
-            writeString((String) v);
+            return VAL_STRING;
         } else if (v instanceof Integer) {
-            writeInt(VAL_INTEGER);
-            writeInt((Integer) v);
+            return VAL_INTEGER;
         } else if (v instanceof Map) {
-            writeInt(VAL_MAP);
-            writeMap((Map) v);
+            return VAL_MAP;
         } else if (v instanceof Bundle) {
             // Must be before Parcelable
-            writeInt(VAL_BUNDLE);
-            writeBundle((Bundle) v);
+            return VAL_BUNDLE;
         } else if (v instanceof PersistableBundle) {
-            writeInt(VAL_PERSISTABLEBUNDLE);
-            writePersistableBundle((PersistableBundle) v);
+            // Must be before Parcelable
+            return VAL_PERSISTABLEBUNDLE;
+        } else if (v instanceof SizeF) {
+            // Must be before Parcelable
+            return VAL_SIZEF;
         } else if (v instanceof Parcelable) {
             // IMPOTANT: cases for classes that implement Parcelable must
-            // come before the Parcelable case, so that their specific VAL_*
+            // come before the Parcelable case, so that their speci fic VAL_*
             // types will be written.
-            writeInt(VAL_PARCELABLE);
-            writeParcelable((Parcelable) v, 0);
+            return VAL_PARCELABLE;
         } else if (v instanceof Short) {
-            writeInt(VAL_SHORT);
-            writeInt(((Short) v).intValue());
+            return VAL_SHORT;
         } else if (v instanceof Long) {
-            writeInt(VAL_LONG);
-            writeLong((Long) v);
+            return VAL_LONG;
         } else if (v instanceof Float) {
-            writeInt(VAL_FLOAT);
-            writeFloat((Float) v);
+            return VAL_FLOAT;
         } else if (v instanceof Double) {
-            writeInt(VAL_DOUBLE);
-            writeDouble((Double) v);
+            return VAL_DOUBLE;
         } else if (v instanceof Boolean) {
-            writeInt(VAL_BOOLEAN);
-            writeInt((Boolean) v ? 1 : 0);
+            return VAL_BOOLEAN;
         } else if (v instanceof CharSequence) {
             // Must be after String
-            writeInt(VAL_CHARSEQUENCE);
-            writeCharSequence((CharSequence) v);
+            return VAL_CHARSEQUENCE;
         } else if (v instanceof List) {
-            writeInt(VAL_LIST);
-            writeList((List) v);
+            return VAL_LIST;
         } else if (v instanceof SparseArray) {
-            writeInt(VAL_SPARSEARRAY);
-            writeSparseArray((SparseArray) v);
+            return VAL_SPARSEARRAY;
         } else if (v instanceof boolean[]) {
-            writeInt(VAL_BOOLEANARRAY);
-            writeBooleanArray((boolean[]) v);
+            return VAL_BOOLEANARRAY;
         } else if (v instanceof byte[]) {
-            writeInt(VAL_BYTEARRAY);
-            writeByteArray((byte[]) v);
+            return VAL_BYTEARRAY;
         } else if (v instanceof String[]) {
-            writeInt(VAL_STRINGARRAY);
-            writeStringArray((String[]) v);
+            return VAL_STRINGARRAY;
         } else if (v instanceof CharSequence[]) {
             // Must be after String[] and before Object[]
-            writeInt(VAL_CHARSEQUENCEARRAY);
-            writeCharSequenceArray((CharSequence[]) v);
+            return VAL_CHARSEQUENCEARRAY;
         } else if (v instanceof IBinder) {
-            writeInt(VAL_IBINDER);
-            writeStrongBinder((IBinder) v);
+            return VAL_IBINDER;
         } else if (v instanceof Parcelable[]) {
-            writeInt(VAL_PARCELABLEARRAY);
-            writeParcelableArray((Parcelable[]) v, 0);
+            return VAL_PARCELABLEARRAY;
         } else if (v instanceof int[]) {
-            writeInt(VAL_INTARRAY);
-            writeIntArray((int[]) v);
+            return VAL_INTARRAY;
         } else if (v instanceof long[]) {
-            writeInt(VAL_LONGARRAY);
-            writeLongArray((long[]) v);
+            return VAL_LONGARRAY;
         } else if (v instanceof Byte) {
-            writeInt(VAL_BYTE);
-            writeInt((Byte) v);
+            return VAL_BYTE;
         } else if (v instanceof Size) {
-            writeInt(VAL_SIZE);
-            writeSize((Size) v);
-        } else if (v instanceof SizeF) {
-            writeInt(VAL_SIZEF);
-            writeSizeF((SizeF) v);
+            return VAL_SIZE;
         } else if (v instanceof double[]) {
-            writeInt(VAL_DOUBLEARRAY);
-            writeDoubleArray((double[]) v);
+            return VAL_DOUBLEARRAY;
         } else {
             Class<?> clazz = v.getClass();
             if (clazz.isArray() && clazz.getComponentType() == Object.class) {
                 // Only pure Object[] are written here, Other arrays of non-primitive types are
                 // handled by serialization as this does not record the component type.
-                writeInt(VAL_OBJECTARRAY);
-                writeArray((Object[]) v);
+                return VAL_OBJECTARRAY;
             } else if (v instanceof Serializable) {
                 // Must be last
-                writeInt(VAL_SERIALIZABLE);
-                writeSerializable((Serializable) v);
+                return VAL_SERIALIZABLE;
             } else {
-                throw new RuntimeException("Parcel: unable to marshal value " + v);
+                throw new IllegalArgumentException("Parcel: unknown type for value " + v);
             }
         }
     }
+    /**
+     * Writes value {@code v} in the parcel. This does NOT write the int representing the type
+     * first.
+     *
+     * @hide
+     */
+    public void writeValue(int type, @Nullable Object v) {
+        switch (type) {
+            case VAL_NULL:
+                break;
+            case VAL_STRING:
+                writeString((String) v);
+                break;
+            case VAL_INTEGER:
+                writeInt((Integer) v);
+                break;
+            case VAL_MAP:
+                writeMap((Map) v);
+                break;
+            case VAL_BUNDLE:
+                writeBundle((Bundle) v);
+                break;
+            case VAL_PERSISTABLEBUNDLE:
+                writePersistableBundle((PersistableBundle) v);
+                break;
+            case VAL_PARCELABLE:
+                writeParcelable((Parcelable) v, 0);
+                break;
+            case VAL_SHORT:
+                writeInt(((Short) v).intValue());
+                break;
+            case VAL_LONG:
+                writeLong((Long) v);
+                break;
+            case VAL_FLOAT:
+                writeFloat((Float) v);
+                break;
+            case VAL_DOUBLE:
+                writeDouble((Double) v);
+                break;
+            case VAL_BOOLEAN:
+                writeInt((Boolean) v ? 1 : 0);
+                break;
+            case VAL_CHARSEQUENCE:
+                writeCharSequence((CharSequence) v);
+                break;
+            case VAL_LIST:
+                writeList((List) v);
+                break;
+            case VAL_SPARSEARRAY:
+                writeSparseArray((SparseArray) v);
+                break;
+            case VAL_BOOLEANARRAY:
+                writeBooleanArray((boolean[]) v);
+                break;
+            case VAL_BYTEARRAY:
+                writeByteArray((byte[]) v);
+                break;
+            case VAL_STRINGARRAY:
+                writeStringArray((String[]) v);
+                break;
+            case VAL_CHARSEQUENCEARRAY:
+                writeCharSequenceArray((CharSequence[]) v);
+                break;
+            case VAL_IBINDER:
+                writeStrongBinder((IBinder) v);
+                break;
+            case VAL_PARCELABLEARRAY:
+                writeParcelableArray((Parcelable[]) v, 0);
+                break;
+            case VAL_INTARRAY:
+                writeIntArray((int[]) v);
+                break;
+            case VAL_LONGARRAY:
+                writeLongArray((long[]) v);
+                break;
+            case VAL_BYTE:
+                writeInt((Byte) v);
+                break;
+            case VAL_SIZE:
+                writeSize((Size) v);
+                break;
+            case VAL_SIZEF:
+                writeSizeF((SizeF) v);
+                break;
+            case VAL_DOUBLEARRAY:
+                writeDoubleArray((double[]) v);
+                break;
+            case VAL_OBJECTARRAY:
+                writeArray((Object[]) v);
+                break;
+            case VAL_SERIALIZABLE:
+                writeSerializable((Serializable) v);
+                break;
+            default:
+                throw new RuntimeException("Parcel: unable to marshal value " + v);
+        }
+    }
 
     /**
      * Flatten the name of the class of the Parcelable and its contents
@@ -3208,7 +3369,180 @@
     @Nullable
     public final Object readValue(@Nullable ClassLoader loader) {
         int type = readInt();
+        final Object object;
+        if (isLengthPrefixed(type)) {
+            int length = readInt();
+            int start = dataPosition();
+            object = readValue(type, loader);
+            int actual = dataPosition() - start;
+            if (actual != length) {
+                Log.w(TAG,
+                        "Unparcelling of " + object + " of type " + Parcel.valueTypeToString(type)
+                                + "  consumed " + actual + " bytes, but " + length + " expected.");
+            }
+        } else {
+            object = readValue(type, loader);
+        }
+        return object;
+    }
 
+    /**
+     * This will return a {@link Supplier} for length-prefixed types that deserializes the object
+     * when {@link Supplier#get()} is called, for other types it will return the object itself.
+     *
+     * <p>After calling {@link Supplier#get()} the parcel cursor will not change. Note that you
+     * shouldn't recycle the parcel, not at least until all objects have been retrieved. No
+     * synchronization attempts are made.
+     *
+     * </p>The supplier returned implements {@link #equals(Object)} and {@link #hashCode()}. Two
+     * suppliers are equal if either of the following is true:
+     * <ul>
+     *   <li>{@link Supplier#get()} has been called on both and both objects returned are equal.
+     *   <li>{@link Supplier#get()} hasn't been called on either one and everything below is true:
+     *   <ul>
+     *       <li>The {@code loader} parameters used to retrieve each are equal.
+     *       <li>They both have the same type.
+     *       <li>They have the same payload length.
+     *       <li>Their binary content is the same.
+     *   </ul>
+     * </ul>
+     *
+     * @hide
+     */
+    @Nullable
+    public Object readLazyValue(@Nullable ClassLoader loader) {
+        int start = dataPosition();
+        int type = readInt();
+        if (isLengthPrefixed(type)) {
+            int length = readInt();
+            setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
+            return new LazyValue(this, start, length, type, loader);
+        } else {
+            return readValue(type, loader);
+        }
+    }
+
+    private static final class LazyValue implements Supplier<Object> {
+        private final int mPosition;
+        private final int mLength;
+        private final int mType;
+        @Nullable private final ClassLoader mLoader;
+        @Nullable private Parcel mSource;
+        @Nullable private Object mObject;
+        @Nullable private Parcel mValueParcel;
+
+        LazyValue(Parcel source, int position, int length, int type, @Nullable ClassLoader loader) {
+            mSource = source;
+            mPosition = position;
+            mLength = length;
+            mType = type;
+            mLoader = loader;
+        }
+
+        @Override
+        public Object get() {
+            if (mObject == null) {
+                int restore = mSource.dataPosition();
+                try {
+                    mSource.setDataPosition(mPosition);
+                    mObject = mSource.readValue(mLoader);
+                } finally {
+                    mSource.setDataPosition(restore);
+                }
+                mSource = null;
+                if (mValueParcel != null) {
+                    mValueParcel.recycle();
+                    mValueParcel = null;
+                }
+            }
+            return mObject;
+        }
+
+        public void writeToParcel(Parcel out) {
+            if (mObject == null) {
+                int restore = mSource.dataPosition();
+                try {
+                    mSource.setDataPosition(mPosition);
+                    out.writeInt(mSource.readInt()); // Type
+                    out.writeInt(mSource.readInt()); // Length
+                    out.appendFrom(mSource, mSource.dataPosition(), mLength);
+                } finally {
+                    mSource.setDataPosition(restore);
+                }
+            } else {
+                out.writeValue(mObject);
+            }
+        }
+
+        public boolean hasFileDescriptors() {
+            return getValueParcel().hasFileDescriptors();
+        }
+
+        @Override
+        public String toString() {
+            return mObject == null
+                    ? "Supplier{" + valueTypeToString(mType) + "@" + mPosition + "+" + mLength + '}'
+                    : "Supplier{" + mObject + "}";
+        }
+
+        /**
+         * We're checking if the *lazy value* is equal to another one, not if the *object*
+         * represented by the lazy value is equal to the other one. So, if there are two lazy values
+         * and one of them has been deserialized but the other hasn't this will always return false.
+         */
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            if (!(other instanceof LazyValue)) {
+                return false;
+            }
+            LazyValue value = (LazyValue) other;
+            // Check if they are either both serialized or both deserialized
+            if ((mObject == null) != (value.mObject == null)) {
+                return false;
+            }
+            // If both are deserialized, compare the live objects
+            if (mObject != null) {
+                return mObject.equals(value.mObject);
+            }
+            // Better safely fail here since this could mean we get different objects
+            if (!Objects.equals(mLoader, value.mLoader)) {
+                return false;
+            }
+            // Otherwise compare metadata prior to comparing payload
+            if (mType != value.mType || mLength != value.mLength) {
+                return false;
+            }
+            // Finally we compare the payload
+            return getValueParcel().compareData(value.getValueParcel()) == 0;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mObject, mLoader, mType, mLength);
+        }
+
+        /** This extracts the parcel section responsible for the object and returns it. */
+        private Parcel getValueParcel() {
+            if (mValueParcel == null) {
+                mValueParcel = Parcel.obtain();
+                // mLength is the length of object representation, excluding the type and length.
+                // mPosition is the position of the entire value container, right before the type.
+                // So, we add 4 bytes for the type + 4 bytes for the length written.
+                mValueParcel.appendFrom(mSource, mPosition, mLength + 8);
+            }
+            return mValueParcel;
+        }
+    }
+
+    /**
+     * Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
+     * type first.
+     */
+    @Nullable
+    private Object readValue(int type, @Nullable ClassLoader loader) {
         switch (type) {
         case VAL_NULL:
             return null;
@@ -3307,6 +3641,20 @@
         }
     }
 
+    private boolean isLengthPrefixed(int type) {
+        switch (type) {
+            case VAL_PARCELABLE:
+            case VAL_PARCELABLEARRAY:
+            case VAL_LIST:
+            case VAL_SPARSEARRAY:
+            case VAL_BUNDLE:
+            case VAL_SERIALIZABLE:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     /**
      * Read and return a new Parcelable from the parcel.  The given class loader
      * will be used to load any enclosed Parcelables.  If it is null, the default
@@ -3609,49 +3957,49 @@
         }
     }
 
-    /* package */ void readArrayMapInternal(@NonNull ArrayMap outVal, int N,
-            @Nullable ClassLoader loader) {
-        if (DEBUG_ARRAY_MAP) {
-            RuntimeException here =  new RuntimeException("here");
-            here.fillInStackTrace();
-            Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
-        }
-        int startPos;
-        while (N > 0) {
-            if (DEBUG_ARRAY_MAP) startPos = dataPosition();
-            String key = readString();
-            Object value = readValue(loader);
-            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read #" + (N-1) + " "
-                    + (dataPosition()-startPos) + " bytes: key=0x"
-                    + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
-            outVal.append(key, value);
-            N--;
-        }
-        outVal.validate();
+    /* package */ void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal,
+            int size, @Nullable ClassLoader loader) {
+        readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loader);
     }
 
-    /* package */ void readArrayMapSafelyInternal(@NonNull ArrayMap outVal, int N,
-            @Nullable ClassLoader loader) {
-        if (DEBUG_ARRAY_MAP) {
-            RuntimeException here =  new RuntimeException("here");
-            here.fillInStackTrace();
-            Log.d(TAG, "Reading safely " + N + " ArrayMap entries", here);
-        }
-        while (N > 0) {
+    /**
+     * Reads a map into {@code map}.
+     *
+     * @param sorted Whether the keys are sorted by their hashes, if so we use an optimized path.
+     * @param lazy   Whether to populate the map with lazy {@link Supplier} objects for
+     *               length-prefixed values. See {@link Parcel#readLazyValue(ClassLoader)} for more
+     *               details.
+     * @return whether the parcel can be recycled or not.
+     * @hide
+     */
+    boolean readArrayMap(ArrayMap<? super String, Object> map, int size, boolean sorted,
+            boolean lazy, @Nullable ClassLoader loader) {
+        boolean recycle = true;
+        while (size > 0) {
             String key = readString();
-            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read safe #" + (N-1) + ": key=0x"
-                    + (key != null ? key.hashCode() : 0) + " " + key);
-            Object value = readValue(loader);
-            outVal.put(key, value);
-            N--;
+            Object value = (lazy) ? readLazyValue(loader) : readValue(loader);
+            if (value instanceof LazyValue) {
+                recycle = false;
+            }
+            if (sorted) {
+                map.append(key, value);
+            } else {
+                map.put(key, value);
+            }
+            size--;
         }
+        if (sorted) {
+            map.validate();
+        }
+        return recycle;
     }
 
     /**
      * @hide For testing only.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void readArrayMap(@NonNull ArrayMap outVal, @Nullable ClassLoader loader) {
+    public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal,
+            @Nullable ClassLoader loader) {
         final int N = readInt();
         if (N < 0) {
             return;
@@ -3736,4 +4084,38 @@
     public long getBlobAshmemSize() {
         return nativeGetBlobAshmemSize(mNativePtr);
     }
+
+    private static String valueTypeToString(int type) {
+        switch (type) {
+            case VAL_NULL: return "VAL_NULL";
+            case VAL_INTEGER: return "VAL_INTEGER";
+            case VAL_MAP: return "VAL_MAP";
+            case VAL_BUNDLE: return "VAL_BUNDLE";
+            case VAL_PERSISTABLEBUNDLE: return "VAL_PERSISTABLEBUNDLE";
+            case VAL_PARCELABLE: return "VAL_PARCELABLE";
+            case VAL_SHORT: return "VAL_SHORT";
+            case VAL_LONG: return "VAL_LONG";
+            case VAL_FLOAT: return "VAL_FLOAT";
+            case VAL_DOUBLE: return "VAL_DOUBLE";
+            case VAL_BOOLEAN: return "VAL_BOOLEAN";
+            case VAL_CHARSEQUENCE: return "VAL_CHARSEQUENCE";
+            case VAL_LIST: return "VAL_LIST";
+            case VAL_SPARSEARRAY: return "VAL_SPARSEARRAY";
+            case VAL_BOOLEANARRAY: return "VAL_BOOLEANARRAY";
+            case VAL_BYTEARRAY: return "VAL_BYTEARRAY";
+            case VAL_STRINGARRAY: return "VAL_STRINGARRAY";
+            case VAL_CHARSEQUENCEARRAY: return "VAL_CHARSEQUENCEARRAY";
+            case VAL_IBINDER: return "VAL_IBINDER";
+            case VAL_PARCELABLEARRAY: return "VAL_PARCELABLEARRAY";
+            case VAL_INTARRAY: return "VAL_INTARRAY";
+            case VAL_LONGARRAY: return "VAL_LONGARRAY";
+            case VAL_BYTE: return "VAL_BYTE";
+            case VAL_SIZE: return "VAL_SIZE";
+            case VAL_SIZEF: return "VAL_SIZEF";
+            case VAL_DOUBLEARRAY: return "VAL_DOUBLEARRAY";
+            case VAL_OBJECTARRAY: return "VAL_OBJECTARRAY";
+            case VAL_SERIALIZABLE: return "VAL_SERIALIZABLE";
+            default: return "UNKNOWN(" + type + ")";
+        }
+    }
 }
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/ServiceManager.java b/core/java/android/os/ServiceManager.java
index f853e67..06a2c87 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -17,6 +17,8 @@
 package android.os;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -28,6 +30,7 @@
 import java.util.Map;
 
 /** @hide */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class ServiceManager {
     private static final String TAG = "ServiceManager";
     private static final Object sLock = new Object();
@@ -98,10 +101,12 @@
         int COUNT = GET_SERVICE + 1;
     }
 
+    /** @hide */
     public static final StatLogger sStatLogger = new StatLogger(new String[] {
             "getService()",
     });
 
+    /** @hide */
     @UnsupportedAppUsage
     public ServiceManager() {
     }
@@ -123,6 +128,7 @@
      *
      * @param name the name of the service to get
      * @return a reference to the service, or <code>null</code> if the service doesn't exist
+     * @hide
      */
     @UnsupportedAppUsage
     public static IBinder getService(String name) {
@@ -160,6 +166,7 @@
      *
      * @param name the name of the new service
      * @param service the service object
+     * @hide
      */
     @UnsupportedAppUsage
     public static void addService(String name, IBinder service) {
@@ -174,6 +181,7 @@
      * @param service the service object
      * @param allowIsolated set to true to allow isolated sandboxed processes
      * to access this service
+     * @hide
      */
     @UnsupportedAppUsage
     public static void addService(String name, IBinder service, boolean allowIsolated) {
@@ -189,6 +197,7 @@
      * @param allowIsolated set to true to allow isolated sandboxed processes
      * @param dumpPriority supported dump priority levels as a bitmask
      * to access this service
+     * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static void addService(String name, IBinder service, boolean allowIsolated,
@@ -203,6 +212,7 @@
     /**
      * Retrieve an existing service called @a name from the
      * service manager.  Non-blocking.
+     * @hide
      */
     @UnsupportedAppUsage
     public static IBinder checkService(String name) {
@@ -239,6 +249,7 @@
      *
      * @return true if the service is declared somewhere (eg. VINTF manifest) and
      * waitForService should always be able to return the service.
+     * @hide
      */
     public static String[] getDeclaredInstances(@NonNull String iface) {
         try {
@@ -256,8 +267,13 @@
      * will wait for it to be ready.
      *
      * @return {@code null} only if there are permission problems or fatal errors.
+     * @hide
      */
-    public static native IBinder waitForService(@NonNull String name);
+    public static IBinder waitForService(@NonNull String name) {
+        return Binder.allowBlocking(waitForServiceNative(name));
+    }
+
+    private static native IBinder waitForServiceNative(@NonNull String name);
 
     /**
      * Returns the specified service from the service manager, if declared.
@@ -267,8 +283,10 @@
      *
      * @return {@code null} if the service is not declared in the manifest, or if there are
      * permission problems, or if there are fatal errors.
+     * @hide
      */
-    public static IBinder waitForDeclaredService(@NonNull String name) {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @Nullable public static IBinder waitForDeclaredService(@NonNull String name) {
         return isDeclared(name) ? waitForService(name) : null;
     }
 
@@ -276,6 +294,7 @@
      * Return a list of all currently running services.
      * @return an array of all currently running services, or <code>null</code> in
      * case of an exception
+     * @hide
      */
     @UnsupportedAppUsage
     public static String[] listServices() {
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index f9b1695..46eb2ec 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -95,15 +94,23 @@
     }
 
     /**
-     * Creates from existing shared memory passed as {@link ParcelFileDesciptor}.
+     * Creates an instance from existing shared memory passed as {@link ParcelFileDescriptor}.
      *
-     * @param fd File descriptor of shared memory passed as {@link #ParcelFileDescriptor}.
+     * <p> The {@code fd} should be a shared memory created from
+       {@code SharedMemory or ASharedMemory}. This can be useful when shared memory is passed as
+       file descriptor through JNI or binder service implemented in cpp.
+     * <p> Note that newly created {@code SharedMemory} takes ownership of passed {@code fd} and
+     * the original {@code fd} becomes detached (Check {@link ParcelFileDescriptor#detachFd()}).
+     * If the caller wants to use the file descriptor after the call, the caller should duplicate
+     * the file descriptor (Check {@link ParcelFileDescriptor#dup()}) and pass the duped version
+     * instead.
      *
-     * @hide
+     * @param fd File descriptor of shared memory passed as {@link ParcelFileDescriptor}.
      */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public static @NonNull SharedMemory create(@NonNull ParcelFileDescriptor fd) {
-        return new SharedMemory(fd.getFileDescriptor());
+    public static @NonNull SharedMemory fromFileDescriptor(@NonNull ParcelFileDescriptor fd) {
+        FileDescriptor f = new FileDescriptor();
+        f.setInt$(fd.detachFd());
+        return new SharedMemory(f);
     }
 
     private static final int PROT_MASK = OsConstants.PROT_READ | OsConstants.PROT_WRITE
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/services/core/java/com/android/server/utils/DeviceConfigInterface.java b/core/java/android/provider/DeviceConfigInterface.java
similarity index 63%
rename from services/core/java/com/android/server/utils/DeviceConfigInterface.java
rename to core/java/android/provider/DeviceConfigInterface.java
index ff60903..0a888f4 100644
--- a/services/core/java/com/android/server/utils/DeviceConfigInterface.java
+++ b/core/java/android/provider/DeviceConfigInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,57 +14,103 @@
  * limitations under the License.
  */
 
-package com.android.server.utils;
+package android.provider;
+
+import static android.provider.Settings.ResetMode;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.BadConfigException;
+import android.provider.DeviceConfig.Properties;
 
 import java.util.concurrent.Executor;
 
 /**
  * Abstraction around {@link DeviceConfig} to allow faking device configuration in tests.
+ *
+ * @hide
  */
 public interface DeviceConfigInterface {
+
     /**
+     * @hide
      * @see DeviceConfig#getProperty
      */
     @Nullable
     String getProperty(@NonNull String namespace, @NonNull String name);
 
     /**
+     * @hide
+     * @see DeviceConfig#getProperties
+     */
+    @NonNull
+    Properties getProperties(@NonNull String namespace, @NonNull String... names);
+
+    /**
+     * @hide
+     * @see DeviceConfig#setProperty
+     */
+    boolean setProperty(@NonNull String namespace, @NonNull String name, @Nullable String value,
+            boolean makeDefault);
+
+    /**
+     * @hide
+     * @see DeviceConfig#setProperties
+     */
+    boolean setProperties(@NonNull Properties properties) throws BadConfigException;
+
+    /**
+     * @hide
+     * @see DeviceConfig#deleteProperty
+     */
+    boolean deleteProperty(@NonNull String namespace, @NonNull String name);
+
+    /**
+     * @hide
+     * @see DeviceConfig#resetToDefaults
+     */
+    void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace);
+
+    /**
+     * @hide
      * @see DeviceConfig#getString
      */
     @NonNull
     String getString(@NonNull String namespace, @NonNull String name, @NonNull String defaultValue);
 
     /**
+     * @hide
      * @see DeviceConfig#getInt
      */
     int getInt(@NonNull String namespace, @NonNull String name, int defaultValue);
 
     /**
+     * @hide
      * @see DeviceConfig#getLong
      */
     long getLong(@NonNull String namespace, @NonNull String name, long defaultValue);
 
     /**
+     * @hide
      * @see DeviceConfig#getBoolean
      */
     boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue);
 
     /**
+     * @hide
      * @see DeviceConfig#getFloat
      */
     float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue);
 
     /**
+     * @hide
      * @see DeviceConfig#addOnPropertiesChangedListener
      */
     void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor,
             @NonNull DeviceConfig.OnPropertiesChangedListener listener);
 
     /**
+     * @hide
      * @see DeviceConfig#removeOnPropertiesChangedListener
      */
     void removeOnPropertiesChangedListener(
@@ -72,7 +118,10 @@
 
     /**
      * Calls through to the real {@link DeviceConfig}.
+     *
+     * @hide
      */
+    @NonNull
     DeviceConfigInterface REAL = new DeviceConfigInterface() {
         @Override
         public String getProperty(String namespace, String name) {
@@ -80,6 +129,36 @@
         }
 
         @Override
+        public DeviceConfig.Properties getProperties(@NonNull String namespace,
+                @NonNull String... names) {
+            return DeviceConfig.getProperties(namespace, names);
+        }
+
+        @Override
+        public boolean setProperty(@NonNull String namespace,
+                @NonNull String name,
+                @Nullable String value, boolean makeDefault) {
+            return DeviceConfig.setProperty(namespace, name, value, makeDefault);
+        }
+
+        @Override
+        public boolean setProperties(@NonNull Properties properties)
+                throws BadConfigException {
+            return DeviceConfig.setProperties(properties);
+        }
+
+        @Override
+        public boolean deleteProperty(@NonNull String namespace,
+                @NonNull String name) {
+            return DeviceConfig.deleteProperty(namespace, name);
+        }
+
+        @Override
+        public void resetToDefaults(int resetMode, @Nullable String namespace) {
+            DeviceConfig.resetToDefaults(resetMode, namespace);
+        }
+
+        @Override
         public String getString(String namespace, String name, String defaultValue) {
             return DeviceConfig.getString(namespace, name, defaultValue);
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4dfa6c3..a5b76d3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10221,6 +10221,13 @@
                 "device_state_rotation_lock";
 
         /**
+         * Control whether communal mode is allowed on this device.
+         *
+         * @hide
+         */
+        public static final String COMMUNAL_MODE_ENABLED = "communal_mode_enabled";
+
+        /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
          */
@@ -10367,6 +10374,14 @@
                 "enable_accessibility_global_gesture_enabled";
 
         /**
+         * Whether select sound track with audio description by default.
+         * @hide
+         */
+        @Readable
+        public static final String ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT =
+                "enable_accessibility_audio_description_by_default";
+
+        /**
          * Whether Airplane Mode is on.
          */
         @Readable
@@ -11960,6 +11975,12 @@
         public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed";
 
         /**
+         * Whether UWB should be enabled.
+         * @hide
+         */
+        public static final String UWB_ENABLED = "uwb_enabled";
+
+        /**
          * Value to specify whether network quality scores and badging should be shown in the UI.
          *
          * Type: int (0 for false, 1 for true)
@@ -13511,6 +13532,54 @@
         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
@@ -15068,6 +15137,16 @@
                 "power_button_long_press";
 
         /**
+         * Override internal R.integer.config_longPressOnPowerDurationMs. It determines the length
+         * of power button press to be considered a long press in milliseconds.
+         * Used by PhoneWindowManager.
+         * @hide
+         */
+        @Readable
+        public static final String POWER_BUTTON_LONG_PRESS_DURATION_MS =
+                "power_button_long_press_duration_ms";
+
+        /**
          * Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
          * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
          * Used by PhoneWindowManager.
@@ -15390,9 +15469,27 @@
          */
         public static int getInt(ContentResolver cr, String name, int def) {
             String v = getString(cr, name);
+            final boolean isQueryForDeviceProvision = name.equals(DEVICE_PROVISIONED);
             try {
-                return v != null ? Integer.parseInt(v) : def;
+                // TODO(b/197879371): remove the extra logging after bug is fixed
+                final int result;
+                if (v != null) {
+                    result = Integer.parseInt(v);
+                    if (isQueryForDeviceProvision) {
+                        Log.w(TAG, "Found settings value for provision. Returning " + result);
+                    }
+                } else {
+                    result = def;
+                    if (isQueryForDeviceProvision) {
+                        Log.w(TAG, "Missing settings value for provision. Returning " + result);
+                    }
+                }
+                return result;
             } catch (NumberFormatException e) {
+                if (isQueryForDeviceProvision) {
+                    Log.w(TAG, "Wrong settings value for provision. Found: " + v
+                            + ". Returning " + v);
+                }
                 return def;
             }
         }
@@ -16847,6 +16944,29 @@
              * @hide
              */
             public static final String COMBINED_LOCATION_ENABLED = "combined_location_enable";
+
+            /**
+             * The wrist orientation mode of the device
+             * Valid values - LEFT_WRIST_ROTATION_0 = "0" (default), LEFT_WRIST_ROTATION_180 = "1",
+             *          RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3"
+             * @hide
+             */
+            public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode";
+
+            /**
+             * Setting indicating the name of the Wear OS app package containing the device's sysui.
+             *
+             * @hide
+             */
+            public static final String CLOCKWORK_SYSUI_PACKAGE = "clockwork_sysui_package";
+
+            /**
+             * Setting indicating the name of the main activity of the Wear OS sysui.
+             *
+             * @hide
+             */
+            public static final String CLOCKWORK_SYSUI_MAIN_ACTIVITY =
+                    "clockwork_sysui_main_activity";
         }
     }
 
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 45bdb11..c1d5a28 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1051,9 +1051,8 @@
         if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CONVERSATIONS,
                 isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CONVERSATIONS, defaultPolicy))) {
             priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
-            conversationSenders = getNotificationPolicySenders(
-                    zenPolicy.getPriorityConversationSenders(),
-                    conversationSenders);
+            conversationSenders = getConversationSendersWithDefault(
+                    zenPolicy.getPriorityConversationSenders(), conversationSenders);
         }
 
         if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
@@ -1166,6 +1165,17 @@
         }
     }
 
+    private int getConversationSendersWithDefault(@ZenPolicy.ConversationSenders int senders,
+            int defaultPolicySender) {
+        switch (senders) {
+            case ZenPolicy.CONVERSATION_SENDERS_ANYONE:
+            case ZenPolicy.CONVERSATION_SENDERS_IMPORTANT:
+            case ZenPolicy.CONVERSATION_SENDERS_NONE:
+                return senders;
+            default:
+                return defaultPolicySender;
+        }
+    }
 
     /**
      * Maps NotificationManager.Policy senders type to ZenPolicy.PeopleType
@@ -1216,7 +1226,8 @@
         }
         priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
         priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
-        priorityConversationSenders = allowConversationsFrom;
+        priorityConversationSenders = getConversationSendersWithDefault(
+                allowConversationsFrom, priorityConversationSenders);
 
         return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
                 suppressedVisualEffects, areChannelsBypassingDnd
diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java
index 93c006a..756a70c 100644
--- a/core/java/android/service/translation/TranslationService.java
+++ b/core/java/android/service/translation/TranslationService.java
@@ -29,6 +29,7 @@
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
+import android.content.pm.ParceledListSlice;
 import android.os.BaseBundle;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -38,7 +39,6 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.util.ArraySet;
 import android.util.Log;
 import android.view.translation.ITranslationDirectManager;
 import android.view.translation.ITranslationServiceCallback;
@@ -51,6 +51,7 @@
 
 import com.android.internal.os.IResultReceiver;
 
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -366,10 +367,11 @@
                                     + "format compatibility");
                         }
 
-                        final ArraySet<TranslationCapability> capabilities = new ArraySet<>(values);
                         final Bundle bundle = new Bundle();
-                        bundle.putParcelableArray(TranslationManager.EXTRA_CAPABILITIES,
-                                capabilities.toArray(new TranslationCapability[0]));
+                        final ParceledListSlice<TranslationCapability> listSlice =
+                                new ParceledListSlice<>(Arrays.asList(
+                                        values.toArray(new TranslationCapability[0])));
+                        bundle.putParcelable(TranslationManager.EXTRA_CAPABILITIES, listSlice);
                         resultReceiver.send(STATUS_SYNC_CALL_SUCCESS, bundle);
                     }
                 });
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/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 4edff27..f50b51b 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -27,6 +27,7 @@
 import java.util.ConcurrentModificationException;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.BiConsumer;
 
 /**
  * ArrayMap is a generic key->value mapping data structure that is
@@ -980,6 +981,28 @@
     }
 
     /**
+     * Performs the given action for all elements in the stored order. This implementation overrides
+     * the default implementation to avoid iterating using the {@link #entrySet()} and iterates in
+     * the key-value order consistent with {@link #keyAt(int)} and {@link #valueAt(int)}.
+     *
+     * @param action The action to be performed for each element
+     */
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) {
+            throw new NullPointerException("action must not be null");
+        }
+
+        final int size = mSize;
+        for (int i = 0; i < size; ++i) {
+            if (size != mSize) {
+                throw new ConcurrentModificationException();
+            }
+            action.accept(keyAt(i), valueAt(i));
+        }
+    }
+
+    /**
      * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>map</var>
      * @param map The map whose contents are to be retrieved.
      */
diff --git a/core/java/android/util/DisplayUtils.java b/core/java/android/util/DisplayUtils.java
new file mode 100644
index 0000000..4fe7f83
--- /dev/null
+++ b/core/java/android/util/DisplayUtils.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 android.util;
+
+import android.content.res.Resources;
+
+import com.android.internal.R;
+
+/**
+ * Utils for loading resources for multi-display.
+ *
+ * @hide
+ */
+public class DisplayUtils {
+
+    /**
+     * 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.
+     */
+    public static int getDisplayUniqueIdConfigIndex(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;
+    }
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 6c3c383..3d39fbe 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -51,6 +51,9 @@
     /** @hide */
     public static final String SETTINGS_ENABLE_SECURITY_HUB = "settings_enable_security_hub";
 
+    /** @hide */
+    public static final String SETTINGS_SUPPORT_LARGE_SCREEN = "settings_support_large_screen";
+
     private static final Map<String, String> DEFAULT_FLAGS;
 
     static {
@@ -72,12 +75,14 @@
         DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "true");
         DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true");
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
+        DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "false");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
     static {
         PERSISTENT_FLAGS = new HashSet<>();
         PERSISTENT_FLAGS.add(SETTINGS_PROVIDER_MODEL);
+        PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
     }
 
     /**
diff --git a/core/java/android/util/SparseArrayMap.java b/core/java/android/util/SparseArrayMap.java
index 590ba1a..cd592a7 100644
--- a/core/java/android/util/SparseArrayMap.java
+++ b/core/java/android/util/SparseArrayMap.java
@@ -175,7 +175,7 @@
     public void forEach(@NonNull TriConsumer<K, V> consumer) {
         for (int iIdx = numMaps() - 1; iIdx >= 0; --iIdx) {
             final int i = mData.keyAt(iIdx);
-            final ArrayMap<K, V> data = mData.valueAt(i);
+            final ArrayMap<K, V> data = mData.valueAt(iIdx);
             for (int kIdx = data.size() - 1; kIdx >= 0; --kIdx) {
                 consumer.accept(i, data.keyAt(kIdx), data.valueAt(kIdx));
             }
diff --git a/core/java/android/util/apk/OWNERS b/core/java/android/util/apk/OWNERS
index 52c9550..0f4e869 100644
--- a/core/java/android/util/apk/OWNERS
+++ b/core/java/android/util/apk/OWNERS
@@ -1 +1,3 @@
 include /core/java/android/content/pm/OWNERS
+cbrubaker@google.com
+mpgroover@google.com
diff --git a/core/java/android/util/apk/TEST_MAPPING b/core/java/android/util/apk/TEST_MAPPING
index 4598b4f..e182521 100644
--- a/core/java/android/util/apk/TEST_MAPPING
+++ b/core/java/android/util/apk/TEST_MAPPING
@@ -1,6 +1,16 @@
 {
   "presubmit": [
     {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.util.apk.SourceStampVerifierTest"
+        }
+      ]
+    }
+  ],
+  "presubmit-large": [
+    {
       "name": "CtsContentTestCases",
       "options": [
         {
@@ -10,14 +20,6 @@
           "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
         }
       ]
-    },
-    {
-      "name": "FrameworksCoreTests",
-      "options": [
-        {
-          "include-filter": "android.util.apk.SourceStampVerifierTest"
-        }
-      ]
     }
   ]
 }
diff --git a/core/java/android/uwb/AdapterStateListener.java b/core/java/android/uwb/AdapterStateListener.java
deleted file mode 100644
index 7e82cc6..0000000
--- a/core/java/android/uwb/AdapterStateListener.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.NonNull;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.uwb.UwbManager.AdapterStateCallback;
-import android.uwb.UwbManager.AdapterStateCallback.State;
-import android.uwb.UwbManager.AdapterStateCallback.StateChangedReason;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
-    private static final String TAG = "Uwb.StateListener";
-
-    private final IUwbAdapter mAdapter;
-    private boolean mIsRegistered = false;
-
-    private final Map<AdapterStateCallback, Executor> mCallbackMap = new HashMap<>();
-
-    @StateChangedReason
-    private int mAdapterStateChangeReason = AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
-    @State
-    private int mAdapterState = AdapterStateCallback.STATE_DISABLED;
-
-    public AdapterStateListener(@NonNull IUwbAdapter adapter) {
-        mAdapter = adapter;
-    }
-
-    /**
-     * Register an {@link AdapterStateCallback} with this {@link AdapterStateListener}
-     *
-     * @param executor an {@link Executor} to execute given callback
-     * @param callback user implementation of the {@link AdapterStateCallback}
-     */
-    public void register(@NonNull Executor executor, @NonNull AdapterStateCallback callback) {
-        synchronized (this) {
-            if (mCallbackMap.containsKey(callback)) {
-                return;
-            }
-
-            mCallbackMap.put(callback, executor);
-
-            if (!mIsRegistered) {
-                try {
-                    mAdapter.registerAdapterStateCallbacks(this);
-                    mIsRegistered = true;
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to register adapter state callback");
-                    throw e.rethrowFromSystemServer();
-                }
-            } else {
-                sendCurrentState(callback);
-            }
-        }
-    }
-
-    /**
-     * Unregister the specified {@link AdapterStateCallback}
-     *
-     * @param callback user implementation of the {@link AdapterStateCallback}
-     */
-    public void unregister(@NonNull AdapterStateCallback callback) {
-        synchronized (this) {
-            if (!mCallbackMap.containsKey(callback)) {
-                return;
-            }
-
-            mCallbackMap.remove(callback);
-
-            if (mCallbackMap.isEmpty() && mIsRegistered) {
-                try {
-                    mAdapter.unregisterAdapterStateCallbacks(this);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
-                    throw e.rethrowFromSystemServer();
-                }
-                mIsRegistered = false;
-            }
-        }
-    }
-
-    /**
-     * Sets the adapter enabled state
-     *
-     * @param isEnabled value of new adapter state
-     */
-    public void setEnabled(boolean isEnabled) {
-        synchronized (this) {
-            try {
-                mAdapter.setEnabled(isEnabled);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to set adapter state");
-                throw e.rethrowFromSystemServer();
-            }
-
-        }
-    }
-
-    /**
-     * Gets the adapter enabled state
-     *
-     * @return integer representing adapter enabled state
-     */
-    public int getAdapterState() {
-        synchronized (this) {
-            try {
-                return mAdapter.getAdapterState();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to get adapter state");
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    private void sendCurrentState(@NonNull AdapterStateCallback callback) {
-        synchronized (this) {
-            Executor executor = mCallbackMap.get(callback);
-
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                executor.execute(() -> callback.onStateChanged(
-                        mAdapterState, mAdapterStateChangeReason));
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void onAdapterStateChanged(int state, int reason) {
-        synchronized (this) {
-            @StateChangedReason int localReason =
-                    convertToStateChangedReason(reason);
-            @State int localState = convertToState(state);
-            mAdapterStateChangeReason = localReason;
-            mAdapterState = localState;
-            for (AdapterStateCallback cb : mCallbackMap.keySet()) {
-                sendCurrentState(cb);
-            }
-        }
-    }
-
-    private static @StateChangedReason int convertToStateChangedReason(
-            @StateChangeReason int reason) {
-        switch (reason) {
-            case StateChangeReason.ALL_SESSIONS_CLOSED:
-                return AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED;
-
-            case StateChangeReason.SESSION_STARTED:
-                return AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED;
-
-            case StateChangeReason.SYSTEM_POLICY:
-                return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY;
-
-            case StateChangeReason.SYSTEM_BOOT:
-                return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT;
-
-            case StateChangeReason.UNKNOWN:
-            default:
-                return AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
-        }
-    }
-
-    private static @State int convertToState(@AdapterState int state) {
-        switch (state) {
-            case AdapterState.STATE_ENABLED_INACTIVE:
-                return AdapterStateCallback.STATE_ENABLED_INACTIVE;
-
-            case AdapterState.STATE_ENABLED_ACTIVE:
-                return AdapterStateCallback.STATE_ENABLED_ACTIVE;
-
-            case AdapterState.STATE_DISABLED:
-            default:
-                return AdapterStateCallback.STATE_DISABLED;
-        }
-    }
-}
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
deleted file mode 100644
index 3d60373..0000000
--- a/core/java/android/uwb/AngleMeasurement.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.FloatRange;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Angle measurement
- *
- * <p>The actual angle is interpreted as:
- *   {@link #getRadians()} +/- {@link #getErrorRadians()} ()} at {@link #getConfidenceLevel()}
- *
- * @hide
- */
-@SystemApi
-public final class AngleMeasurement implements Parcelable {
-    private final double mRadians;
-    private final double mErrorRadians;
-    private final double mConfidenceLevel;
-
-    /**
-     * Constructs a new {@link AngleMeasurement} object
-     *
-     * @param radians the angle in radians
-     * @param errorRadians the error of the angle measurement in radians
-     * @param confidenceLevel confidence level of the angle measurement
-     *
-     * @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of
-     *                                  allowed range
-     */
-    public AngleMeasurement(
-            @FloatRange(from = -Math.PI, to = +Math.PI) double radians,
-            @FloatRange(from = 0.0, to = +Math.PI) double errorRadians,
-            @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
-        if (radians < -Math.PI || radians > Math.PI) {
-            throw new IllegalArgumentException("Invalid radians: " + radians);
-        }
-        mRadians = radians;
-
-        if (errorRadians < 0.0 || errorRadians > Math.PI) {
-            throw new IllegalArgumentException("Invalid error radians: " + errorRadians);
-        }
-        mErrorRadians = errorRadians;
-
-        if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
-            throw new IllegalArgumentException("Invalid confidence level: " + confidenceLevel);
-        }
-        mConfidenceLevel = confidenceLevel;
-    }
-
-    /**
-     * Angle measurement in radians
-     *
-     * @return angle in radians
-     */
-    @FloatRange(from = -Math.PI, to = +Math.PI)
-    public double getRadians() {
-        return mRadians;
-    }
-
-    /**
-     * Error of angle measurement in radians
-     *
-     * <p>Must be a positive value
-     *
-     * @return angle measurement error in radians
-     */
-    @FloatRange(from = 0.0, to = +Math.PI)
-    public double getErrorRadians() {
-        return mErrorRadians;
-    }
-
-    /**
-     * Angle measurement confidence level expressed as a value between
-     * 0.0 to 1.0.
-     *
-     * <p>A value of 0.0 indicates there is no confidence in the measurement. A value of 1.0
-     * indicates there is maximum confidence in the measurement.
-     *
-     * @return the confidence level of the angle measurement
-     */
-    @FloatRange(from = 0.0, to = 1.0)
-    public double getConfidenceLevel() {
-        return mConfidenceLevel;
-    }
-
-    /**
-     * @hide
-    */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj instanceof AngleMeasurement) {
-            AngleMeasurement other = (AngleMeasurement) obj;
-            return mRadians == other.getRadians()
-                    && mErrorRadians == other.getErrorRadians()
-                    && mConfidenceLevel == other.getConfidenceLevel();
-        }
-        return false;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hash(mRadians, mErrorRadians, mConfidenceLevel);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeDouble(mRadians);
-        dest.writeDouble(mErrorRadians);
-        dest.writeDouble(mConfidenceLevel);
-    }
-
-    public static final @android.annotation.NonNull Creator<AngleMeasurement> CREATOR =
-            new Creator<AngleMeasurement>() {
-                @Override
-                public AngleMeasurement createFromParcel(Parcel in) {
-                    return new AngleMeasurement(in.readDouble(), in.readDouble(), in.readDouble());
-                }
-
-                @Override
-                public AngleMeasurement[] newArray(int size) {
-                    return new AngleMeasurement[size];
-                }
-    };
-}
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
deleted file mode 100644
index db04ad1..0000000
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Represents an angle of arrival measurement between two devices using Ultra Wideband
- *
- * @hide
- */
-@SystemApi
-public final class AngleOfArrivalMeasurement implements Parcelable {
-    private final AngleMeasurement mAzimuthAngleMeasurement;
-    private final AngleMeasurement mAltitudeAngleMeasurement;
-
-    private AngleOfArrivalMeasurement(@NonNull AngleMeasurement azimuthAngleMeasurement,
-            @Nullable AngleMeasurement altitudeAngleMeasurement) {
-        mAzimuthAngleMeasurement = azimuthAngleMeasurement;
-        mAltitudeAngleMeasurement = altitudeAngleMeasurement;
-    }
-
-    /**
-     * Azimuth angle measurement
-     * <p>Azimuth {@link AngleMeasurement} of remote device in horizontal coordinate system, this is
-     * the angle clockwise from the meridian when viewing above the north pole.
-     *
-     * <p>See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
-     *
-     * <p>On an Android device, azimuth north is defined as the angle perpendicular away from the
-     * back of the device when holding it in portrait mode upright.
-     *
-     * <p>Azimuth angle must be supported when Angle of Arrival is supported
-     *
-     * @return the azimuth {@link AngleMeasurement}
-     */
-    @NonNull
-    public AngleMeasurement getAzimuth() {
-        return mAzimuthAngleMeasurement;
-    }
-
-    /**
-     * Altitude angle measurement
-     * <p>Altitude {@link AngleMeasurement} of remote device in horizontal coordinate system, this
-     * is the angle above the equator when the north pole is up.
-     *
-     * <p>See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
-     *
-     * <p>On an Android device, altitude is defined as the angle vertical from ground when holding
-     * the device in portrait mode upright.
-     *
-     * @return altitude {@link AngleMeasurement} or null when this is not available
-     */
-    @Nullable
-    public AngleMeasurement getAltitude() {
-        return mAltitudeAngleMeasurement;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj instanceof AngleOfArrivalMeasurement) {
-            AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
-            return mAzimuthAngleMeasurement.equals(other.getAzimuth())
-                    && mAltitudeAngleMeasurement.equals(other.getAltitude());
-        }
-        return false;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hash(mAzimuthAngleMeasurement, mAltitudeAngleMeasurement);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mAzimuthAngleMeasurement, flags);
-        dest.writeParcelable(mAltitudeAngleMeasurement, flags);
-    }
-
-    public static final @android.annotation.NonNull Creator<AngleOfArrivalMeasurement> CREATOR =
-            new Creator<AngleOfArrivalMeasurement>() {
-                @Override
-                public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
-                    Builder builder =
-                            new Builder(in.readParcelable(AngleMeasurement.class.getClassLoader()));
-
-                    builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
-
-                    return builder.build();
-                }
-
-                @Override
-                public AngleOfArrivalMeasurement[] newArray(int size) {
-                    return new AngleOfArrivalMeasurement[size];
-                }
-            };
-
-    /**
-     * Builder class for {@link AngleOfArrivalMeasurement}.
-     */
-    public static final class Builder {
-        private final AngleMeasurement mAzimuthAngleMeasurement;
-        private AngleMeasurement mAltitudeAngleMeasurement = null;
-
-        /**
-         * Constructs an {@link AngleOfArrivalMeasurement} object
-         *
-         * @param azimuthAngle the azimuth angle of the measurement
-         */
-        public Builder(@NonNull AngleMeasurement azimuthAngle) {
-            mAzimuthAngleMeasurement = azimuthAngle;
-        }
-
-        /**
-         * Set the altitude angle
-         *
-         * @param altitudeAngle altitude angle
-         */
-        @NonNull
-        public Builder setAltitude(@NonNull AngleMeasurement altitudeAngle) {
-            mAltitudeAngleMeasurement = altitudeAngle;
-            return this;
-        }
-
-        /**
-         * Build the {@link AngleOfArrivalMeasurement} object
-         */
-        @NonNull
-        public AngleOfArrivalMeasurement build() {
-            return new AngleOfArrivalMeasurement(mAzimuthAngleMeasurement,
-                    mAltitudeAngleMeasurement);
-        }
-    }
-}
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
deleted file mode 100644
index 9856553..0000000
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.FloatRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * A data point for the distance measurement
- *
- * <p>The actual distance is interpreted as:
- *   {@link #getMeters()} +/- {@link #getErrorMeters()} at {@link #getConfidenceLevel()}
- *
- * @hide
- */
-@SystemApi
-public final class DistanceMeasurement implements Parcelable {
-    private final double mMeters;
-    private final double mErrorMeters;
-    private final double mConfidenceLevel;
-
-    private DistanceMeasurement(double meters, double errorMeters, double confidenceLevel) {
-        mMeters = meters;
-        mErrorMeters = errorMeters;
-        mConfidenceLevel = confidenceLevel;
-    }
-
-    /**
-     * Distance measurement in meters
-     *
-     * @return distance in meters
-     */
-    public double getMeters() {
-        return mMeters;
-    }
-
-    /**
-     * Error of distance measurement in meters
-     * <p>Must be positive
-     *
-     * @return error of distance measurement in meters
-     */
-    @FloatRange(from = 0.0)
-    public double getErrorMeters() {
-        return mErrorMeters;
-    }
-
-    /**
-     * Distance measurement confidence level expressed as a value between 0.0 to 1.0.
-     *
-     * <p>A value of 0.0 indicates no confidence in the measurement. A value of 1.0 represents
-     * maximum confidence in the measurement
-     *
-     * @return confidence level
-     */
-    @FloatRange(from = 0.0, to = 1.0)
-    public double getConfidenceLevel() {
-        return mConfidenceLevel;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj instanceof DistanceMeasurement) {
-            DistanceMeasurement other = (DistanceMeasurement) obj;
-            return mMeters == other.getMeters()
-                    && mErrorMeters == other.getErrorMeters()
-                    && mConfidenceLevel == other.getConfidenceLevel();
-        }
-        return false;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hash(mMeters, mErrorMeters, mConfidenceLevel);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeDouble(mMeters);
-        dest.writeDouble(mErrorMeters);
-        dest.writeDouble(mConfidenceLevel);
-    }
-
-    public static final @android.annotation.NonNull Creator<DistanceMeasurement> CREATOR =
-            new Creator<DistanceMeasurement>() {
-                @Override
-                public DistanceMeasurement createFromParcel(Parcel in) {
-                    Builder builder = new Builder();
-                    builder.setMeters(in.readDouble());
-                    builder.setErrorMeters(in.readDouble());
-                    builder.setConfidenceLevel(in.readDouble());
-                    return builder.build();
-                }
-
-                @Override
-                public DistanceMeasurement[] newArray(int size) {
-                    return new DistanceMeasurement[size];
-                }
-    };
-
-    /**
-     * Builder to get a {@link DistanceMeasurement} object.
-     */
-    public static final class Builder {
-        private double mMeters = Double.NaN;
-        private double mErrorMeters = Double.NaN;
-        private double mConfidenceLevel = Double.NaN;
-
-        /**
-         * Set the distance measurement in meters
-         *
-         * @param meters distance in meters
-         * @throws IllegalArgumentException if meters is NaN
-         */
-        @NonNull
-        public Builder setMeters(double meters) {
-            if (Double.isNaN(meters)) {
-                throw new IllegalArgumentException("meters cannot be NaN");
-            }
-            mMeters = meters;
-            return this;
-        }
-
-        /**
-         * Set the distance error in meters
-         *
-         * @param errorMeters distance error in meters
-         * @throws IllegalArgumentException if error is negative or NaN
-         */
-        @NonNull
-        public Builder setErrorMeters(@FloatRange(from = 0.0) double errorMeters) {
-            if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
-                throw new IllegalArgumentException(
-                        "errorMeters must be >= 0.0 and not NaN: " + errorMeters);
-            }
-            mErrorMeters = errorMeters;
-            return this;
-        }
-
-        /**
-         * Set the confidence level
-         *
-         * @param confidenceLevel the confidence level in the distance measurement
-         * @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
-         */
-        @NonNull
-        public Builder setConfidenceLevel(
-                @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
-            if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
-                throw new IllegalArgumentException(
-                        "confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
-            }
-            mConfidenceLevel = confidenceLevel;
-            return this;
-        }
-
-        /**
-         * Builds the {@link DistanceMeasurement} object
-         *
-         * @throws IllegalStateException if meters, error, or confidence are not set
-         */
-        @NonNull
-        public DistanceMeasurement build() {
-            if (Double.isNaN(mMeters)) {
-                throw new IllegalStateException("Meters cannot be NaN");
-            }
-
-            if (Double.isNaN(mErrorMeters)) {
-                throw new IllegalStateException("Error meters cannot be NaN");
-            }
-
-            if (Double.isNaN(mConfidenceLevel)) {
-                throw new IllegalStateException("Confidence level cannot be NaN");
-            }
-
-            return new DistanceMeasurement(mMeters, mErrorMeters, mConfidenceLevel);
-        }
-    }
-}
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
deleted file mode 100644
index d879350..0000000
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.content.AttributionSource;
-import android.os.PersistableBundle;
-import android.uwb.IUwbAdapterStateCallbacks;
-import android.uwb.IUwbRangingCallbacks;
-import android.uwb.SessionHandle;
-
-/**
- * @hide
- */
-interface IUwbAdapter {
-  /*
-   * Register the callbacks used to notify the framework of events and data
-   *
-   * The provided callback's IUwbAdapterStateCallbacks#onAdapterStateChanged
-   * function must be called immediately following registration with the current
-   * state of the UWB adapter.
-   *
-   * @param callbacks callback to provide range and status updates to the framework
-   */
-  void registerAdapterStateCallbacks(in IUwbAdapterStateCallbacks adapterStateCallbacks);
-
-  /*
-   * Unregister the callbacks used to notify the framework of events and data
-   *
-   * Calling this function with an unregistered callback is a no-op
-   *
-   * @param callbacks callback to unregister
-   */
-  void unregisterAdapterStateCallbacks(in IUwbAdapterStateCallbacks callbacks);
-
-  /**
-   * Get the accuracy of the ranging timestamps
-   *
-   * @return accuracy of the ranging timestamps in nanoseconds
-   */
-  long getTimestampResolutionNanos();
-
-  /**
-   * Provides the capabilities and features of the device
-   *
-   * @return specification specific capabilities and features of the device
-   */
-  PersistableBundle getSpecificationInfo();
-
-  /**
-   * Request to open a new ranging session
-   *
-   * This function does not start the ranging session, but all necessary
-   * components must be initialized and ready to start a new ranging
-   * session prior to calling IUwbAdapterCallback#onRangingOpened.
-   *
-   * IUwbAdapterCallbacks#onRangingOpened must be called within
-   * RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being
-   * called if the ranging session is opened successfully.
-   *
-   * IUwbAdapterCallbacks#onRangingOpenFailed must be called within
-   * RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being called
-   * if the ranging session fails to be opened.
-   *
-   * If the provided sessionHandle is already open for the calling client, then
-   * #onRangingOpenFailed must be called and the new session must not be opened.
-   *
-   * @param attributionSource AttributionSource to use for permission enforcement.
-   * @param sessionHandle the session handle to open ranging for
-   * @param rangingCallbacks the callbacks used to deliver ranging information
-   * @param parameters the configuration to use for ranging
-   */
-  void openRanging(in AttributionSource attributionSource,
-                   in SessionHandle sessionHandle,
-                   in IUwbRangingCallbacks rangingCallbacks,
-                   in PersistableBundle parameters);
-
-  /**
-   * Request to start ranging
-   *
-   * IUwbAdapterCallbacks#onRangingStarted must be called within
-   * RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being
-   * called if the ranging session starts successfully.
-   *
-   * IUwbAdapterCallbacks#onRangingStartFailed must be called within
-   * RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being
-   * called if the ranging session fails to be started.
-   *
-   * @param sessionHandle the session handle to start ranging for
-   * @param parameters additional configuration required to start ranging
-   */
-  void startRanging(in SessionHandle sessionHandle,
-                    in PersistableBundle parameters);
-
-  /**
-   * Request to reconfigure ranging
-   *
-   * IUwbAdapterCallbacks#onRangingReconfigured must be called after
-   * successfully reconfiguring the session.
-   *
-   * IUwbAdapterCallbacks#onRangingReconfigureFailed must be called after
-   * failing to reconfigure the session.
-   *
-   * A session must not be modified by a failed call to #reconfigureRanging.
-   *
-   * @param sessionHandle the session handle to start ranging for
-   * @param parameters the parameters to reconfigure and their new values
-   */
-  void reconfigureRanging(in SessionHandle sessionHandle,
-                          in PersistableBundle parameters);
-
-  /**
-   * Request to stop ranging
-   *
-   * IUwbAdapterCallbacks#onRangingStopped must be called after
-   * successfully stopping the session.
-   *
-   * IUwbAdapterCallbacks#onRangingStopFailed must be called after failing
-   * to stop the session.
-   *
-   * @param sessionHandle the session handle to stop ranging for
-   */
-  void stopRanging(in SessionHandle sessionHandle);
-
-  /**
-   * Close ranging for the session associated with the given handle
-   *
-   * Calling with an invalid handle or a handle that has already been closed
-   * is a no-op.
-   *
-   * IUwbAdapterCallbacks#onRangingClosed must be called within
-   * RANGING_SESSION_CLOSE_THRESHOLD_MS of #closeRanging being called.
-   *
-   * @param sessionHandle the session handle to close ranging for
-   */
-  void closeRanging(in SessionHandle sessionHandle);
-
-   /**
-     * Disables or enables UWB for a user
-     *
-     * The provided callback's IUwbAdapterStateCallbacks#onAdapterStateChanged
-     * function must be called immediately following state change.
-     *
-     * @param enabled value representing intent to disable or enable UWB. If
-     * true, any subsequent calls to #openRanging will be allowed. If false,
-     * all active ranging sessions will be closed and subsequent calls to
-     * #openRanging will be disallowed.
-     */
-    void setEnabled(boolean enabled);
-
-   /**
-    * Returns the current enabled/disabled UWB state.
-    *
-    * Possible values are:
-    * IUwbAdapterState#STATE_DISABLED
-    * IUwbAdapterState#STATE_ENABLED_ACTIVE
-    * IUwbAdapterState#STATE_ENABLED_INACTIVE
-    *
-    * @return value representing enabled/disabled UWB state.
-    */
-   int getAdapterState();
-
-  /**
-   * The maximum allowed time to open a ranging session.
-   */
-  const int RANGING_SESSION_OPEN_THRESHOLD_MS = 3000; // Value TBD
-
-  /**
-   * The maximum allowed time to start a ranging session.
-   */
-  const int RANGING_SESSION_START_THRESHOLD_MS = 3000; // Value TBD
-
-  /**
-   * The maximum allowed time to notify the framework that a session has been
-   * closed.
-   */
-  const int RANGING_SESSION_CLOSE_THRESHOLD_MS = 3000; // Value TBD
-}
diff --git a/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl b/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl
deleted file mode 100644
index d3b34c6..0000000
--- a/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.uwb.StateChangeReason;
-import android.uwb.AdapterState;
-
-/**
- * @hide
- */
-interface IUwbAdapterStateCallbacks {
-  /**
-     * Called whenever the adapter state changes
-     *
-     * @param state UWB state; enabled_active, enabled_inactive, or disabled.
-     * @param reason the reason that the state has changed
-     */
-    void onAdapterStateChanged(AdapterState state, StateChangeReason reason);
-}
\ No newline at end of file
diff --git a/core/java/android/uwb/IUwbRangingCallbacks.aidl b/core/java/android/uwb/IUwbRangingCallbacks.aidl
deleted file mode 100644
index 555bafe..0000000
--- a/core/java/android/uwb/IUwbRangingCallbacks.aidl
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.os.PersistableBundle;
-import android.uwb.RangingChangeReason;
-import android.uwb.RangingReport;
-import android.uwb.SessionHandle;
-
-/**
- * @hide
- */
-oneway interface IUwbRangingCallbacks {
-  /**
-   * Called when the ranging session has been opened
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   */
-  void onRangingOpened(in SessionHandle sessionHandle);
-
-  /**
-   * Called when a ranging session fails to start
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param reason the reason the session failed to start
-   * @param parameters protocol specific parameters
-   */
-  void onRangingOpenFailed(in SessionHandle sessionHandle,
-                           RangingChangeReason reason,
-                           in PersistableBundle parameters);
-
-  /**
-   * Called when ranging has started
-   *
-   * May output parameters generated by the lower layers that must be sent to the
-   * remote device(s). The PersistableBundle must be constructed using the UWB
-   * support library.
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param rangingOutputParameters parameters generated by the lower layer that
-   *                                should be sent to the remote device.
-   */
-  void onRangingStarted(in SessionHandle sessionHandle,
-                        in PersistableBundle parameters);
-
-  /**
-   * Called when a ranging session fails to start
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param reason the reason the session failed to start
-   * @param parameters protocol specific parameters
-   */
-  void onRangingStartFailed(in SessionHandle sessionHandle,
-                            RangingChangeReason reason,
-                            in PersistableBundle parameters);
-
-   /**
-   * Called when ranging has been reconfigured
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param parameters the updated ranging configuration
-   */
-  void onRangingReconfigured(in SessionHandle sessionHandle,
-                             in PersistableBundle parameters);
-
-  /**
-   * Called when a ranging session fails to be reconfigured
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param reason the reason the session failed to reconfigure
-   * @param parameters protocol specific parameters
-   */
-  void onRangingReconfigureFailed(in SessionHandle sessionHandle,
-                                  RangingChangeReason reason,
-                                  in PersistableBundle parameters);
-
-  /**
-   * Called when the ranging session has been stopped
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param reason the reason the session was stopped
-   * @param parameters protocol specific parameters
-   */
-
-  void onRangingStopped(in SessionHandle sessionHandle,
-                        RangingChangeReason reason,
-                        in PersistableBundle parameters);
-
-  /**
-   * Called when a ranging session fails to stop
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param reason the reason the session failed to stop
-   * @param parameters protocol specific parameters
-   */
-  void onRangingStopFailed(in SessionHandle sessionHandle,
-                           RangingChangeReason reason,
-                           in PersistableBundle parameters);
-
-  /**
-   * Called when a ranging session is closed
-   *
-   * @param sessionHandle the session the callback is being invoked for
-   * @param reason the reason the session was closed
-   * @param parameters protocol specific parameters
-   */
-  void onRangingClosed(in SessionHandle sessionHandle,
-                       RangingChangeReason reason,
-                       in PersistableBundle parameters);
-
-  /**
-   * Provides a new RangingResult to the framework
-   *
-   * The reported timestamp for a ranging measurement must be calculated as the
-   * time which the ranging round that generated this measurement concluded.
-   *
-   * @param sessionHandle an identifier to associate the ranging results with a
-   *                      session that is active
-   * @param result the ranging report
-   */
-  void onRangingResult(in SessionHandle sessionHandle, in RangingReport result);
-}
diff --git a/core/java/android/uwb/OWNERS b/core/java/android/uwb/OWNERS
deleted file mode 100644
index 17936ae..0000000
--- a/core/java/android/uwb/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-bstack@google.com
-eliptus@google.com
-jsolnit@google.com
-matbev@google.com
-siyuanh@google.com
-zachoverflow@google.com
diff --git a/core/java/android/uwb/RangingChangeReason.aidl b/core/java/android/uwb/RangingChangeReason.aidl
deleted file mode 100644
index 19d4b39..0000000
--- a/core/java/android/uwb/RangingChangeReason.aidl
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-/**
- * @hide
- */
-@Backing(type="int")
-enum RangingChangeReason {
-  /**
-   * Unknown reason
-   */
-  UNKNOWN,
-
-  /**
-   * A local API call triggered the change, such as a call to
-   * IUwbAdapter.closeRanging.
-   */
-  LOCAL_API,
-
-  /**
-   * The maximum number of sessions has been reached. This may be generated for
-   * an active session if a higher priority session begins.
-   */
-  MAX_SESSIONS_REACHED,
-
-  /**
-   * The system state has changed resulting in the session changing (e.g. the
-   * user disables UWB, or the user's locale changes and an active channel is no
-   * longer permitted to be used).
-   */
-  SYSTEM_POLICY,
-
-  /**
-   * The remote device has requested to change the session
-   */
-  REMOTE_REQUEST,
-
-  /**
-   * The session changed for a protocol specific reason
-   */
-  PROTOCOL_SPECIFIC,
-
-  /**
-   * The provided parameters were invalid
-   */
-  BAD_PARAMETERS,
-}
-
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
deleted file mode 100644
index 6bba796..0000000
--- a/core/java/android/uwb/RangingManager.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.NonNull;
-import android.content.AttributionSource;
-import android.os.CancellationSignal;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.Hashtable;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
-    private static final String TAG = "Uwb.RangingManager";
-
-    private final IUwbAdapter mAdapter;
-    private final Hashtable<SessionHandle, RangingSession> mRangingSessionTable = new Hashtable<>();
-    private int mNextSessionId = 1;
-
-    public RangingManager(IUwbAdapter adapter) {
-        mAdapter = adapter;
-    }
-
-    /**
-     * Open a new ranging session
-     *
-     * @param attributionSource Attribution source to use for the enforcement of
-     *                          {@link android.Manifest.permission#ULTRAWIDEBAND_RANGING} runtime
-     *                          permission.
-     * @param params the parameters that define the ranging session
-     * @param executor {@link Executor} to run callbacks
-     * @param callbacks {@link RangingSession.Callback} to associate with the {@link RangingSession}
-     *                  that is being opened.
-     * @return a {@link CancellationSignal} that may be used to cancel the opening of the
-     *         {@link RangingSession}.
-     */
-    public CancellationSignal openSession(@NonNull AttributionSource attributionSource,
-            @NonNull PersistableBundle params,
-            @NonNull Executor executor,
-            @NonNull RangingSession.Callback callbacks) {
-        synchronized (this) {
-            SessionHandle sessionHandle = new SessionHandle(mNextSessionId++);
-            RangingSession session =
-                    new RangingSession(executor, callbacks, mAdapter, sessionHandle);
-            mRangingSessionTable.put(sessionHandle, session);
-            try {
-                mAdapter.openRanging(attributionSource, sessionHandle, this, params);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-
-            CancellationSignal cancellationSignal = new CancellationSignal();
-            cancellationSignal.setOnCancelListener(() -> session.close());
-            return cancellationSignal;
-        }
-    }
-
-    private boolean hasSession(SessionHandle sessionHandle) {
-        return mRangingSessionTable.containsKey(sessionHandle);
-    }
-
-    @Override
-    public void onRangingOpened(SessionHandle sessionHandle) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG,
-                        "onRangingOpened - received unexpected SessionHandle: " + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingOpened();
-        }
-    }
-
-    @Override
-    public void onRangingOpenFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
-            PersistableBundle parameters) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG,
-                        "onRangingOpenedFailed - received unexpected SessionHandle: "
-                                + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingOpenFailed(convertToReason(reason), parameters);
-            mRangingSessionTable.remove(sessionHandle);
-        }
-    }
-
-    @Override
-    public void onRangingReconfigured(SessionHandle sessionHandle, PersistableBundle parameters) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG,
-                        "onRangingReconfigured - received unexpected SessionHandle: "
-                                + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingReconfigured(parameters);
-        }
-    }
-
-    @Override
-    public void onRangingReconfigureFailed(SessionHandle sessionHandle,
-            @RangingChangeReason int reason, PersistableBundle params) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingReconfigureFailed - received unexpected SessionHandle: "
-                        + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingReconfigureFailed(convertToReason(reason), params);
-        }
-    }
-
-
-    @Override
-    public void onRangingStarted(SessionHandle sessionHandle, PersistableBundle parameters) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG,
-                        "onRangingStarted - received unexpected SessionHandle: " + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingStarted(parameters);
-        }
-    }
-
-    @Override
-    public void onRangingStartFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
-            PersistableBundle params) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingStartFailed - received unexpected SessionHandle: "
-                        + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingStartFailed(convertToReason(reason), params);
-        }
-    }
-
-    @Override
-    public void onRangingStopped(SessionHandle sessionHandle, @RangingChangeReason int reason,
-            PersistableBundle params) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingStopped - received unexpected SessionHandle: "
-                        + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingStopped(convertToReason(reason), params);
-        }
-    }
-
-    @Override
-    public void onRangingStopFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
-            PersistableBundle parameters) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingStopFailed - received unexpected SessionHandle: "
-                        + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingStopFailed(convertToReason(reason), parameters);
-        }
-    }
-
-    @Override
-    public void onRangingClosed(SessionHandle sessionHandle, @RangingChangeReason int reason,
-            PersistableBundle params) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingClosed - received unexpected SessionHandle: " + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingClosed(convertToReason(reason), params);
-            mRangingSessionTable.remove(sessionHandle);
-        }
-    }
-
-    @Override
-    public void onRangingResult(SessionHandle sessionHandle, RangingReport result) {
-        synchronized (this) {
-            if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingResult - received unexpected SessionHandle: " + sessionHandle);
-                return;
-            }
-
-            RangingSession session = mRangingSessionTable.get(sessionHandle);
-            session.onRangingResult(result);
-        }
-    }
-
-    @RangingSession.Callback.Reason
-    private static int convertToReason(@RangingChangeReason int reason) {
-        switch (reason) {
-            case RangingChangeReason.LOCAL_API:
-                return RangingSession.Callback.REASON_LOCAL_REQUEST;
-
-            case RangingChangeReason.MAX_SESSIONS_REACHED:
-                return RangingSession.Callback.REASON_MAX_SESSIONS_REACHED;
-
-            case RangingChangeReason.SYSTEM_POLICY:
-                return RangingSession.Callback.REASON_SYSTEM_POLICY;
-
-            case RangingChangeReason.REMOTE_REQUEST:
-                return RangingSession.Callback.REASON_REMOTE_REQUEST;
-
-            case RangingChangeReason.PROTOCOL_SPECIFIC:
-                return RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR;
-
-            case RangingChangeReason.BAD_PARAMETERS:
-                return RangingSession.Callback.REASON_BAD_PARAMETERS;
-
-            case RangingChangeReason.UNKNOWN:
-            default:
-                return RangingSession.Callback.REASON_UNKNOWN;
-        }
-    }
-}
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
deleted file mode 100644
index 249e2b7..0000000
--- a/core/java/android/uwb/RangingMeasurement.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Representation of a ranging measurement between the local device and a remote device
- *
- * @hide
- */
-@SystemApi
-public final class RangingMeasurement implements Parcelable {
-    private final UwbAddress mRemoteDeviceAddress;
-    private final @Status int mStatus;
-    private final long mElapsedRealtimeNanos;
-    private final DistanceMeasurement mDistanceMeasurement;
-    private final AngleOfArrivalMeasurement mAngleOfArrivalMeasurement;
-
-    private RangingMeasurement(@NonNull UwbAddress remoteDeviceAddress, @Status int status,
-            long elapsedRealtimeNanos, @Nullable DistanceMeasurement distanceMeasurement,
-            @Nullable AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
-        mRemoteDeviceAddress = remoteDeviceAddress;
-        mStatus = status;
-        mElapsedRealtimeNanos = elapsedRealtimeNanos;
-        mDistanceMeasurement = distanceMeasurement;
-        mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
-    }
-
-    /**
-     * Get the remote device's {@link UwbAddress}
-     *
-     * @return the remote device's {@link UwbAddress}
-     */
-    @NonNull
-    public UwbAddress getRemoteDeviceAddress() {
-        return mRemoteDeviceAddress;
-    }
-
-    /**
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {
-            RANGING_STATUS_SUCCESS,
-            RANGING_STATUS_FAILURE_OUT_OF_RANGE,
-            RANGING_STATUS_FAILURE_UNKNOWN_ERROR})
-    public @interface Status {}
-
-    /**
-     * Ranging attempt was successful for this device
-     */
-    public static final int RANGING_STATUS_SUCCESS = 0;
-
-    /**
-     * Ranging failed for this device because it is out of range
-     */
-    public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1;
-
-    /**
-     * Ranging failed for this device because of unknown error
-     */
-    public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1;
-
-    /**
-     * Get the status of this ranging measurement
-     *
-     * <p>Possible values are
-     * {@link #RANGING_STATUS_SUCCESS},
-     * {@link #RANGING_STATUS_FAILURE_OUT_OF_RANGE},
-     * {@link #RANGING_STATUS_FAILURE_UNKNOWN_ERROR}.
-     *
-     * @return the status of the ranging measurement
-     */
-    @Status
-    public int getStatus() {
-        return mStatus;
-    }
-
-    /**
-     * Timestamp of this ranging measurement in time since boot nanos in the same namespace as
-     * {@link SystemClock#elapsedRealtimeNanos()}
-     *
-     * @return timestamp of ranging measurement in nanoseconds
-     */
-    @SuppressLint("MethodNameUnits")
-    public long getElapsedRealtimeNanos() {
-        return mElapsedRealtimeNanos;
-    }
-
-    /**
-     * Get the distance measurement
-     *
-     * @return a {@link DistanceMeasurement} or null if {@link #getStatus()} !=
-     *         {@link #RANGING_STATUS_SUCCESS}
-     */
-    @Nullable
-    public DistanceMeasurement getDistanceMeasurement() {
-        return mDistanceMeasurement;
-    }
-
-    /**
-     * Get the angle of arrival measurement
-     *
-     * @return an {@link AngleOfArrivalMeasurement} or null if {@link #getStatus()} !=
-     *         {@link #RANGING_STATUS_SUCCESS}
-     */
-    @Nullable
-    public AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
-        return mAngleOfArrivalMeasurement;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj instanceof RangingMeasurement) {
-            RangingMeasurement other = (RangingMeasurement) obj;
-            return mRemoteDeviceAddress.equals(other.getRemoteDeviceAddress())
-                    && mStatus == other.getStatus()
-                    && mElapsedRealtimeNanos == other.getElapsedRealtimeNanos()
-                    && mDistanceMeasurement.equals(other.getDistanceMeasurement())
-                    && mAngleOfArrivalMeasurement.equals(other.getAngleOfArrivalMeasurement());
-        }
-        return false;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hash(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
-                mDistanceMeasurement, mAngleOfArrivalMeasurement);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mRemoteDeviceAddress, flags);
-        dest.writeInt(mStatus);
-        dest.writeLong(mElapsedRealtimeNanos);
-        dest.writeParcelable(mDistanceMeasurement, flags);
-        dest.writeParcelable(mAngleOfArrivalMeasurement, flags);
-    }
-
-    public static final @android.annotation.NonNull Creator<RangingMeasurement> CREATOR =
-            new Creator<RangingMeasurement>() {
-                @Override
-                public RangingMeasurement createFromParcel(Parcel in) {
-                    Builder builder = new Builder();
-                    builder.setRemoteDeviceAddress(
-                            in.readParcelable(UwbAddress.class.getClassLoader()));
-                    builder.setStatus(in.readInt());
-                    builder.setElapsedRealtimeNanos(in.readLong());
-                    builder.setDistanceMeasurement(
-                            in.readParcelable(DistanceMeasurement.class.getClassLoader()));
-                    builder.setAngleOfArrivalMeasurement(
-                            in.readParcelable(AngleOfArrivalMeasurement.class.getClassLoader()));
-                    return builder.build();
-                }
-
-                @Override
-                public RangingMeasurement[] newArray(int size) {
-                    return new RangingMeasurement[size];
-                }
-    };
-
-    /**
-     * Builder for a {@link RangingMeasurement} object.
-     */
-    public static final class Builder {
-        private UwbAddress mRemoteDeviceAddress = null;
-        private @Status int mStatus = RANGING_STATUS_FAILURE_UNKNOWN_ERROR;
-        private long mElapsedRealtimeNanos = -1L;
-        private DistanceMeasurement mDistanceMeasurement = null;
-        private AngleOfArrivalMeasurement mAngleOfArrivalMeasurement = null;
-
-        /**
-         * Set the remote device address that this measurement is for
-         *
-         * @param remoteDeviceAddress remote device's address
-         */
-        @NonNull
-        public Builder setRemoteDeviceAddress(@NonNull UwbAddress remoteDeviceAddress) {
-            mRemoteDeviceAddress = remoteDeviceAddress;
-            return this;
-        }
-
-        /**
-         * Set the status of ranging measurement
-         *
-         * @param status the status of the ranging measurement
-         */
-        @NonNull
-        public Builder setStatus(@Status int status) {
-            mStatus = status;
-            return this;
-        }
-
-        /**
-         * Set the elapsed realtime in nanoseconds when the ranging measurement occurred
-         *
-         * @param elapsedRealtimeNanos time the ranging measurement occurred
-         */
-        @NonNull
-        public Builder setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
-            if (elapsedRealtimeNanos < 0) {
-                throw new IllegalArgumentException("elapsedRealtimeNanos must be >= 0");
-            }
-            mElapsedRealtimeNanos = elapsedRealtimeNanos;
-            return this;
-        }
-
-        /**
-         * Set the {@link DistanceMeasurement}
-         *
-         * @param distanceMeasurement the distance measurement for this ranging measurement
-         */
-        @NonNull
-        public Builder setDistanceMeasurement(@NonNull DistanceMeasurement distanceMeasurement) {
-            mDistanceMeasurement = distanceMeasurement;
-            return this;
-        }
-
-        /**
-         * Set the {@link AngleOfArrivalMeasurement}
-         *
-         * @param angleOfArrivalMeasurement the angle of arrival measurement for this ranging
-         *                                  measurement
-         */
-        @NonNull
-        public Builder setAngleOfArrivalMeasurement(
-                @NonNull AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
-            mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
-            return this;
-        }
-
-        /**
-         * Build the {@link RangingMeasurement} object
-         *
-         * @throws IllegalStateException if a distance or angle of arrival measurement is provided
-         *                               but the measurement was not successful, if the
-         *                               elapsedRealtimeNanos of the measurement is invalid, or
-         *                               if no remote device address is set
-         */
-        @NonNull
-        public RangingMeasurement build() {
-            if (mStatus != RANGING_STATUS_SUCCESS) {
-                if (mDistanceMeasurement != null) {
-                    throw new IllegalStateException(
-                            "Distance Measurement must be null if ranging is not successful");
-                }
-
-                if (mAngleOfArrivalMeasurement != null) {
-                    throw new IllegalStateException(
-                            "Angle of Arrival must be null if ranging is not successful");
-                }
-            }
-
-            if (mRemoteDeviceAddress == null) {
-                throw new IllegalStateException("No remote device address was set");
-            }
-
-            if (mElapsedRealtimeNanos < 0) {
-                throw new IllegalStateException(
-                        "elapsedRealtimeNanos must be >=0: " + mElapsedRealtimeNanos);
-            }
-
-            return new RangingMeasurement(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
-                    mDistanceMeasurement, mAngleOfArrivalMeasurement);
-        }
-    }
-}
diff --git a/core/java/android/uwb/RangingReport.aidl b/core/java/android/uwb/RangingReport.aidl
deleted file mode 100644
index c32747a..0000000
--- a/core/java/android/uwb/RangingReport.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-parcelable RangingReport;
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
deleted file mode 100644
index 7a2df86..0000000
--- a/core/java/android/uwb/RangingReport.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * This class contains the UWB ranging data
- *
- * @hide
- */
-@SystemApi
-public final class RangingReport implements Parcelable {
-    private final List<RangingMeasurement> mRangingMeasurements;
-
-    private RangingReport(@NonNull List<RangingMeasurement> rangingMeasurements) {
-        mRangingMeasurements = rangingMeasurements;
-    }
-
-    /**
-     * Get a {@link List} of {@link RangingMeasurement} objects in the last measurement interval
-     * <p>The underlying UWB adapter may choose to do multiple measurements in each ranging
-     * interval.
-     *
-     * <p>The entries in the {@link List} are ordered in ascending order based on
-     * {@link RangingMeasurement#getElapsedRealtimeNanos()}
-     *
-     * @return a {@link List} of {@link RangingMeasurement} objects
-     */
-    @NonNull
-    public List<RangingMeasurement> getMeasurements() {
-        return mRangingMeasurements;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj instanceof RangingReport) {
-            RangingReport other = (RangingReport) obj;
-            return mRangingMeasurements.equals(other.getMeasurements());
-        }
-
-        return false;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hash(mRangingMeasurements);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeTypedList(mRangingMeasurements);
-    }
-
-    public static final @android.annotation.NonNull Creator<RangingReport> CREATOR =
-            new Creator<RangingReport>() {
-                @Override
-                public RangingReport createFromParcel(Parcel in) {
-                    Builder builder = new Builder();
-                    builder.addMeasurements(in.createTypedArrayList(RangingMeasurement.CREATOR));
-                    return builder.build();
-                }
-
-                @Override
-                public RangingReport[] newArray(int size) {
-                    return new RangingReport[size];
-                }
-    };
-
-    /**
-     * Builder for {@link RangingReport} object
-     */
-    public static final class Builder {
-        List<RangingMeasurement> mMeasurements = new ArrayList<>();
-
-        /**
-         * Add a single {@link RangingMeasurement}
-         *
-         * @param rangingMeasurement a ranging measurement
-         */
-        @NonNull
-        public Builder addMeasurement(@NonNull RangingMeasurement rangingMeasurement) {
-            mMeasurements.add(rangingMeasurement);
-            return this;
-        }
-
-        /**
-         * Add a {@link List} of {@link RangingMeasurement}s
-         *
-         * @param rangingMeasurements {@link List} of {@link RangingMeasurement}s to add
-         */
-        @NonNull
-        public Builder addMeasurements(@NonNull List<RangingMeasurement> rangingMeasurements) {
-            mMeasurements.addAll(rangingMeasurements);
-            return this;
-        }
-
-        /**
-         * Build the {@link RangingReport} object
-         *
-         * @throws IllegalStateException if measurements are not in monotonically increasing order
-         */
-        @NonNull
-        public RangingReport build() {
-            // Verify that all measurement timestamps are monotonically increasing
-            RangingMeasurement prevMeasurement = null;
-            for (int curIndex = 0; curIndex < mMeasurements.size(); curIndex++) {
-                RangingMeasurement curMeasurement = mMeasurements.get(curIndex);
-                if (prevMeasurement != null
-                        && (prevMeasurement.getElapsedRealtimeNanos()
-                                > curMeasurement.getElapsedRealtimeNanos())) {
-                    throw new IllegalStateException(
-                            "Timestamp (" + curMeasurement.getElapsedRealtimeNanos()
-                            + ") at index " + curIndex + " is less than previous timestamp ("
-                            + prevMeasurement.getElapsedRealtimeNanos() + ")");
-                }
-                prevMeasurement = curMeasurement;
-            }
-            return new RangingReport(mMeasurements);
-        }
-    }
-}
-
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
deleted file mode 100644
index 345b69d..0000000
--- a/core/java/android/uwb/RangingSession.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.Manifest;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.os.Binder;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.concurrent.Executor;
-
-/**
- * This class provides a way to control an active UWB ranging session.
- * <p>It also defines the required {@link RangingSession.Callback} that must be implemented
- * in order to be notified of UWB ranging results and status events related to the
- * {@link RangingSession}.
- *
- * <p>To get an instance of {@link RangingSession}, first use
- * {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)} to request to open a
- * session. Once the session is opened, a {@link RangingSession} object is provided through
- * {@link RangingSession.Callback#onOpened(RangingSession)}. If opening a session fails, the failure
- * is reported through {@link RangingSession.Callback#onOpenFailed(int, PersistableBundle)} with the
- * failure reason.
- *
- * @hide
- */
-@SystemApi
-public final class RangingSession implements AutoCloseable {
-    private static final String TAG = "Uwb.RangingSession";
-    private final SessionHandle mSessionHandle;
-    private final IUwbAdapter mAdapter;
-    private final Executor mExecutor;
-    private final Callback mCallback;
-
-    private enum State {
-        /**
-         * The state of the {@link RangingSession} until
-         * {@link RangingSession.Callback#onOpened(RangingSession)} is invoked
-         */
-        INIT,
-
-        /**
-         * The {@link RangingSession} is initialized and ready to begin ranging
-         */
-        IDLE,
-
-        /**
-         * The {@link RangingSession} is actively ranging
-         */
-        ACTIVE,
-
-        /**
-         * The {@link RangingSession} is closed and may not be used for ranging.
-         */
-        CLOSED
-    }
-
-    private State mState = State.INIT;
-
-    /**
-     * Interface for receiving {@link RangingSession} events
-     */
-    public interface Callback {
-        /**
-         * @hide
-         */
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef(value = {
-                REASON_UNKNOWN,
-                REASON_LOCAL_REQUEST,
-                REASON_REMOTE_REQUEST,
-                REASON_BAD_PARAMETERS,
-                REASON_GENERIC_ERROR,
-                REASON_MAX_SESSIONS_REACHED,
-                REASON_SYSTEM_POLICY,
-                REASON_PROTOCOL_SPECIFIC_ERROR})
-        @interface Reason {}
-
-        /**
-         * Indicates that the session was closed or failed to open due to an unknown reason
-         */
-        int REASON_UNKNOWN = 0;
-
-        /**
-         * Indicates that the session was closed or failed to open because
-         * {@link AutoCloseable#close()} or {@link RangingSession#close()} was called
-         */
-        int REASON_LOCAL_REQUEST = 1;
-
-        /**
-         * Indicates that the session was closed or failed to open due to an explicit request from
-         * the remote device.
-         */
-        int REASON_REMOTE_REQUEST = 2;
-
-        /**
-         * Indicates that the session was closed or failed to open due to erroneous parameters
-         */
-        int REASON_BAD_PARAMETERS = 3;
-
-        /**
-         * Indicates an error on this device besides the error code already listed
-         */
-        int REASON_GENERIC_ERROR = 4;
-
-        /**
-         * Indicates that the number of currently open sessions is equal to
-         * {@link UwbManager#getMaxSimultaneousSessions()} and additional sessions may not be
-         * opened.
-         */
-        int REASON_MAX_SESSIONS_REACHED = 5;
-
-        /**
-         * Indicates that the local system policy caused the change, such
-         * as privacy policy, power management policy, permissions, and more.
-         */
-        int REASON_SYSTEM_POLICY = 6;
-
-        /**
-         * Indicates a protocol specific error. The associated {@link PersistableBundle} should be
-         * consulted for additional information.
-         */
-        int REASON_PROTOCOL_SPECIFIC_ERROR = 7;
-
-        /**
-         * Invoked when {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
-         * is successful
-         *
-         * @param session the newly opened {@link RangingSession}
-         */
-        void onOpened(@NonNull RangingSession session);
-
-        /**
-         * Invoked if {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}}
-         * fails
-         *
-         * @param reason the failure reason
-         * @param params protocol specific parameters
-         */
-        void onOpenFailed(@Reason int reason, @NonNull PersistableBundle params);
-
-        /**
-         * Invoked when {@link RangingSession#start(PersistableBundle)} is successful
-         * @param sessionInfo session specific parameters from the lower layers
-         */
-        void onStarted(@NonNull PersistableBundle sessionInfo);
-
-        /**
-         * Invoked when {@link RangingSession#start(PersistableBundle)} fails
-         *
-         * @param reason the failure reason
-         * @param params protocol specific parameters
-         */
-        void onStartFailed(@Reason int reason, @NonNull PersistableBundle params);
-
-        /**
-         * Invoked when a request to reconfigure the session succeeds
-         *
-         * @param params the updated ranging configuration
-         */
-        void onReconfigured(@NonNull PersistableBundle params);
-
-        /**
-         * Invoked when a request to reconfigure the session fails
-         *
-         * @param reason reason the session failed to be reconfigured
-         * @param params protocol specific failure reasons
-         */
-        void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params);
-
-        /**
-         * Invoked when a request to stop the session succeeds
-         *
-         * @param reason reason for the session stop
-         * @param parameters protocol specific parameters related to the stop reason
-         */
-        void onStopped(@Reason int reason, @NonNull PersistableBundle parameters);
-
-        /**
-         * Invoked when a request to stop the session fails
-         *
-         * @param reason reason the session failed to be stopped
-         * @param params protocol specific failure reasons
-         */
-        void onStopFailed(@Reason int reason, @NonNull PersistableBundle params);
-
-       /**
-         * Invoked when session is either closed spontaneously, or per user request via
-         * {@link RangingSession#close()} or {@link AutoCloseable#close()}.
-         *
-         * @param reason reason for the session closure
-         * @param parameters protocol specific parameters related to the close reason
-         */
-        void onClosed(@Reason int reason, @NonNull PersistableBundle parameters);
-
-        /**
-         * Called once per ranging interval even when a ranging measurement fails
-         *
-         * @param rangingReport ranging report for this interval's measurements
-         */
-        void onReportReceived(@NonNull RangingReport rangingReport);
-    }
-
-    /**
-     * @hide
-     */
-    public RangingSession(Executor executor, Callback callback, IUwbAdapter adapter,
-            SessionHandle sessionHandle) {
-        mState = State.INIT;
-        mExecutor = executor;
-        mCallback = callback;
-        mAdapter = adapter;
-        mSessionHandle = sessionHandle;
-    }
-
-    /**
-     * @hide
-     */
-    public boolean isOpen() {
-        return mState == State.IDLE || mState == State.ACTIVE;
-    }
-
-    /**
-     * Begins ranging for the session.
-     *
-     * <p>On successfully starting a ranging session,
-     * {@link RangingSession.Callback#onStarted(PersistableBundle)} is invoked.
-     *
-     * <p>On failure to start the session,
-     * {@link RangingSession.Callback#onStartFailed(int, PersistableBundle)} is invoked.
-     *
-     * @param params configuration parameters for starting the session
-     */
-    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
-    public void start(@NonNull PersistableBundle params) {
-        if (mState != State.IDLE) {
-            throw new IllegalStateException();
-        }
-
-        try {
-            mAdapter.startRanging(mSessionHandle, params);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Attempts to reconfigure the session with the given parameters
-     * <p>This call may be made when the session is open.
-     *
-     * <p>On successfully reconfiguring the session
-     * {@link RangingSession.Callback#onReconfigured(PersistableBundle)} is invoked.
-     *
-     * <p>On failure to reconfigure the session,
-     * {@link RangingSession.Callback#onReconfigureFailed(int, PersistableBundle)} is invoked.
-     *
-     * @param params the parameters to reconfigure and their new values
-     */
-    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
-    public void reconfigure(@NonNull PersistableBundle params) {
-        if (mState != State.ACTIVE && mState != State.IDLE) {
-            throw new IllegalStateException();
-        }
-
-        try {
-            mAdapter.reconfigureRanging(mSessionHandle, params);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Stops actively ranging
-     *
-     * <p>A session that has been stopped may be resumed by calling
-     * {@link RangingSession#start(PersistableBundle)} without the need to open a new session.
-     *
-     * <p>Stopping a {@link RangingSession} is useful when the lower layers should not discard
-     * the parameters of the session, or when a session needs to be able to be resumed quickly.
-     *
-     * <p>If the {@link RangingSession} is no longer needed, use {@link RangingSession#close()} to
-     * completely close the session and allow lower layers of the stack to perform necessarily
-     * cleanup.
-     *
-     * <p>Stopped sessions may be closed by the system at any time. In such a case,
-     * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} is invoked.
-     *
-     * <p>On failure to stop the session,
-     * {@link RangingSession.Callback#onStopFailed(int, PersistableBundle)} is invoked.
-     */
-    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
-    public void stop() {
-        if (mState != State.ACTIVE) {
-            throw new IllegalStateException();
-        }
-
-        try {
-            mAdapter.stopRanging(mSessionHandle);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Close the ranging session
-     *
-     * <p>After calling this function, in order resume ranging, a new {@link RangingSession} must
-     * be opened by calling
-     * {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}.
-     *
-     * <p>If this session is currently ranging, it will stop and close the session.
-     * <p>If the session is in the process of being opened, it will attempt to stop the session from
-     * being opened.
-     * <p>If the session is already closed, the registered
-     * {@link Callback#onClosed(int, PersistableBundle)} callback will still be invoked.
-     *
-     * <p>{@link Callback#onClosed(int, PersistableBundle)} will be invoked using the same callback
-     * object given to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
-     * when the {@link RangingSession} was opened. The callback will be invoked after each call to
-     * {@link #close()}, even if the {@link RangingSession} is already closed.
-     */
-    @Override
-    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
-    public void close() {
-        if (mState == State.CLOSED) {
-            mExecutor.execute(() -> mCallback.onClosed(
-                    Callback.REASON_LOCAL_REQUEST, new PersistableBundle()));
-            return;
-        }
-
-        try {
-            mAdapter.closeRanging(mSessionHandle);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingOpened() {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingOpened invoked for a closed session");
-            return;
-        }
-
-        mState = State.IDLE;
-        executeCallback(() -> mCallback.onOpened(this));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingOpenFailed(@Callback.Reason int reason,
-            @NonNull PersistableBundle params) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingOpenFailed invoked for a closed session");
-            return;
-        }
-
-        mState = State.CLOSED;
-        executeCallback(() -> mCallback.onOpenFailed(reason, params));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingStarted(@NonNull PersistableBundle parameters) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingStarted invoked for a closed session");
-            return;
-        }
-
-        mState = State.ACTIVE;
-        executeCallback(() -> mCallback.onStarted(parameters));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingStartFailed(@Callback.Reason int reason,
-            @NonNull PersistableBundle params) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingStartFailed invoked for a closed session");
-            return;
-        }
-
-        executeCallback(() -> mCallback.onStartFailed(reason, params));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingReconfigured(@NonNull PersistableBundle params) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingReconfigured invoked for a closed session");
-            return;
-        }
-
-        executeCallback(() -> mCallback.onReconfigured(params));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingReconfigureFailed(@Callback.Reason int reason,
-            @NonNull PersistableBundle params) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingReconfigureFailed invoked for a closed session");
-            return;
-        }
-
-        executeCallback(() -> mCallback.onReconfigureFailed(reason, params));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingStopped(@Callback.Reason int reason,
-            @NonNull PersistableBundle params) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingStopped invoked for a closed session");
-            return;
-        }
-
-        mState = State.IDLE;
-        executeCallback(() -> mCallback.onStopped(reason, params));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingStopFailed(@Callback.Reason int reason,
-            @NonNull PersistableBundle params) {
-        if (mState == State.CLOSED) {
-            Log.w(TAG, "onRangingStopFailed invoked for a closed session");
-            return;
-        }
-
-        executeCallback(() -> mCallback.onStopFailed(reason, params));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingClosed(@Callback.Reason int reason,
-            @NonNull PersistableBundle parameters) {
-        mState = State.CLOSED;
-        executeCallback(() -> mCallback.onClosed(reason, parameters));
-    }
-
-    /**
-     * @hide
-     */
-    public void onRangingResult(@NonNull RangingReport report) {
-        if (!isOpen()) {
-            Log.w(TAG, "onRangingResult invoked for non-open session");
-            return;
-        }
-
-        executeCallback(() -> mCallback.onReportReceived(report));
-    }
-
-    /**
-     * @hide
-     */
-    private void executeCallback(@NonNull Runnable runnable) {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            mExecutor.execute(runnable);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-}
diff --git a/core/java/android/uwb/SessionHandle.java b/core/java/android/uwb/SessionHandle.java
deleted file mode 100644
index b23f5ad..0000000
--- a/core/java/android/uwb/SessionHandle.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * @hide
- */
-public final class SessionHandle implements Parcelable  {
-    private final int mId;
-
-    public SessionHandle(int id) {
-        mId = id;
-    }
-
-    protected SessionHandle(Parcel in) {
-        mId = in.readInt();
-    }
-
-    public static final Creator<SessionHandle> CREATOR = new Creator<SessionHandle>() {
-        @Override
-        public SessionHandle createFromParcel(Parcel in) {
-            return new SessionHandle(in);
-        }
-
-        @Override
-        public SessionHandle[] newArray(int size) {
-            return new SessionHandle[size];
-        }
-    };
-
-    public int getId() {
-        return mId;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mId);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj instanceof SessionHandle) {
-            SessionHandle other = (SessionHandle) obj;
-            return mId == other.mId;
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(mId);
-    }
-
-    @Override
-    public String toString() {
-        return "SessionHandle [id=" + mId + "]";
-    }
-}
diff --git a/core/java/android/uwb/StateChangeReason.aidl b/core/java/android/uwb/StateChangeReason.aidl
deleted file mode 100644
index 28eaf9f..0000000
--- a/core/java/android/uwb/StateChangeReason.aidl
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-/**
- * @hide
- */
-@Backing(type="int")
-enum StateChangeReason {
-  /**
-   * The state changed for an unknown reason
-   */
-  UNKNOWN,
-
-  /**
-   * The adapter state changed because a session started.
-   */
-  SESSION_STARTED,
-
-
-  /**
-   * The adapter state changed because all sessions were closed.
-   */
-  ALL_SESSIONS_CLOSED,
-
-  /**
-   * The adapter state changed because of a device system change.
-   */
-  SYSTEM_POLICY,
-
-  /**
-   * Used to signal the first adapter state message after boot
-   */
-   SYSTEM_BOOT,
-}
-
diff --git a/core/java/android/uwb/TEST_MAPPING b/core/java/android/uwb/TEST_MAPPING
deleted file mode 100644
index 08ed2c7..0000000
--- a/core/java/android/uwb/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "UwbManagerTests"
-    },
-    {
-      "name": "CtsUwbTestCases"
-    }
-  ]
-}
diff --git a/core/java/android/uwb/UwbAddress.aidl b/core/java/android/uwb/UwbAddress.aidl
deleted file mode 100644
index a202b1a..0000000
--- a/core/java/android/uwb/UwbAddress.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-parcelable UwbAddress;
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
deleted file mode 100644
index 22883be..0000000
--- a/core/java/android/uwb/UwbAddress.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * A class representing a UWB address
- *
- * @hide
- */
-@SystemApi
-public final class UwbAddress implements Parcelable {
-    public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
-    public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
-
-    private final byte[] mAddressBytes;
-
-    private UwbAddress(byte[] address) {
-        mAddressBytes = address;
-    }
-
-    /**
-     * Create a {@link UwbAddress} from a byte array.
-     *
-     * <p>If the provided array is {@link #SHORT_ADDRESS_BYTE_LENGTH} bytes, a short address is
-     * created. If the provided array is {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes, then an
-     * extended address is created.
-     *
-     * @param address a byte array to convert to a {@link UwbAddress}
-     * @return a {@link UwbAddress} created from the input byte array
-     * @throws IllegalArgumentException when the length is not one of
-     *       {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes
-     */
-    @NonNull
-    public static UwbAddress fromBytes(@NonNull byte[] address) {
-        if (address.length != SHORT_ADDRESS_BYTE_LENGTH
-                && address.length != EXTENDED_ADDRESS_BYTE_LENGTH) {
-            throw new IllegalArgumentException("Invalid UwbAddress length " + address.length);
-        }
-        return new UwbAddress(address);
-    }
-
-    /**
-     * Get the address as a byte array
-     *
-     * @return the byte representation of this {@link UwbAddress}
-     */
-    @NonNull
-    public byte[] toBytes() {
-        return mAddressBytes;
-    }
-
-    /**
-     * The length of the address in bytes
-     * <p>Possible values are {@link #SHORT_ADDRESS_BYTE_LENGTH} and
-     * {@link #EXTENDED_ADDRESS_BYTE_LENGTH}.
-     */
-    public int size() {
-        return mAddressBytes.length;
-    }
-
-    @NonNull
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder("0x");
-        for (byte addressByte : mAddressBytes) {
-            builder.append(String.format("%02X", addressByte));
-        }
-        return builder.toString();
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (obj instanceof UwbAddress) {
-            return Arrays.equals(mAddressBytes, ((UwbAddress) obj).toBytes());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(mAddressBytes);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mAddressBytes.length);
-        dest.writeByteArray(mAddressBytes);
-    }
-
-    public static final @android.annotation.NonNull Creator<UwbAddress> CREATOR =
-            new Creator<UwbAddress>() {
-                @Override
-                public UwbAddress createFromParcel(Parcel in) {
-                    byte[] address = new byte[in.readInt()];
-                    in.readByteArray(address);
-                    return UwbAddress.fromBytes(address);
-                }
-
-                @Override
-                public UwbAddress[] newArray(int size) {
-                    return new UwbAddress[size];
-                }
-    };
-}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
deleted file mode 100644
index f7406ae..0000000
--- a/core/java/android/uwb/UwbManager.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.Manifest.permission;
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.os.CancellationSignal;
-import android.os.IBinder;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.concurrent.Executor;
-
-/**
- * This class provides a way to perform Ultra Wideband (UWB) operations such as querying the
- * device's capabilities and determining the distance and angle between the local device and a
- * remote device.
- *
- * <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>.
- *
- * @hide
- */
-@SystemApi
-@SystemService(Context.UWB_SERVICE)
-public final class UwbManager {
-    private static final String SERVICE_NAME = Context.UWB_SERVICE;
-
-    private final Context mContext;
-    private final IUwbAdapter mUwbAdapter;
-    private final AdapterStateListener mAdapterStateListener;
-    private final RangingManager mRangingManager;
-
-    /**
-     * Interface for receiving UWB adapter state changes
-     */
-    public interface AdapterStateCallback {
-        /**
-         * @hide
-         */
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef(value = {
-                STATE_CHANGED_REASON_SESSION_STARTED,
-                STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
-                STATE_CHANGED_REASON_SYSTEM_POLICY,
-                STATE_CHANGED_REASON_SYSTEM_BOOT,
-                STATE_CHANGED_REASON_ERROR_UNKNOWN})
-        @interface StateChangedReason {}
-
-        /**
-         * @hide
-         */
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef(value = {
-                STATE_ENABLED_INACTIVE,
-                STATE_ENABLED_ACTIVE,
-                STATE_DISABLED})
-        @interface State {}
-
-        /**
-         * Indicates that the state change was due to opening of first UWB session
-         */
-        int STATE_CHANGED_REASON_SESSION_STARTED = 0;
-
-        /**
-         * Indicates that the state change was due to closure of all UWB sessions
-         */
-        int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1;
-
-        /**
-         * Indicates that the state change was due to changes in system policy
-         */
-        int STATE_CHANGED_REASON_SYSTEM_POLICY = 2;
-
-        /**
-         * Indicates that the current state is due to a system boot
-         */
-        int STATE_CHANGED_REASON_SYSTEM_BOOT = 3;
-
-        /**
-         * Indicates that the state change was due to some unknown error
-         */
-        int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4;
-
-        /**
-         * Indicates that UWB is disabled on device
-         */
-        int STATE_DISABLED = 0;
-        /**
-         * Indicates that UWB is enabled on device but has no active ranging sessions
-         */
-        int STATE_ENABLED_INACTIVE = 1;
-
-        /**
-         * Indicates that UWB is enabled and has active ranging session
-         */
-        int STATE_ENABLED_ACTIVE = 2;
-
-        /**
-         * Invoked when underlying UWB adapter's state is changed
-         * <p>Invoked with the adapter's current state after registering an
-         * {@link AdapterStateCallback} using
-         * {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}.
-         *
-         * <p>Possible reasons for the state to change are
-         * {@link #STATE_CHANGED_REASON_SESSION_STARTED},
-         * {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED},
-         * {@link #STATE_CHANGED_REASON_SYSTEM_POLICY},
-         * {@link #STATE_CHANGED_REASON_SYSTEM_BOOT},
-         * {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}.
-         *
-         * <p>Possible values for the UWB state are
-         * {@link #STATE_ENABLED_INACTIVE},
-         * {@link #STATE_ENABLED_ACTIVE},
-         * {@link #STATE_DISABLED}.
-         *
-         * @param state the UWB state; inactive, active or disabled
-         * @param reason the reason for the state change
-         */
-        void onStateChanged(@State int state, @StateChangedReason int reason);
-    }
-
-    /**
-     * Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance.
-     *
-     * @param ctx Context of the client.
-     * @param adapter an instance of an {@link android.uwb.IUwbAdapter}
-     */
-    private UwbManager(@NonNull Context ctx, @NonNull IUwbAdapter adapter) {
-        mContext = ctx;
-        mUwbAdapter = adapter;
-        mAdapterStateListener = new AdapterStateListener(adapter);
-        mRangingManager = new RangingManager(adapter);
-    }
-
-    /**
-     * @hide
-     */
-    public static UwbManager getInstance(@NonNull Context ctx) {
-        IBinder b = ServiceManager.getService(SERVICE_NAME);
-        if (b == null) {
-            return null;
-        }
-
-        IUwbAdapter adapter = IUwbAdapter.Stub.asInterface(b);
-        if (adapter == null) {
-            return null;
-        }
-
-        return new UwbManager(ctx, adapter);
-    }
-
-    /**
-     * Register an {@link AdapterStateCallback} to listen for UWB adapter state changes
-     * <p>The provided callback will be invoked by the given {@link Executor}.
-     *
-     * <p>When first registering a callback, the callbacks's
-     * {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate
-     * the current state of the underlying UWB adapter with the most recent
-     * {@link AdapterStateCallback.StateChangedReason} that caused the change.
-     *
-     * @param executor an {@link Executor} to execute given callback
-     * @param callback user implementation of the {@link AdapterStateCallback}
-     */
-    @RequiresPermission(permission.UWB_PRIVILEGED)
-    public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull AdapterStateCallback callback) {
-        mAdapterStateListener.register(executor, callback);
-    }
-
-    /**
-     * Unregister the specified {@link AdapterStateCallback}
-     * <p>The same {@link AdapterStateCallback} object used when calling
-     * {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used.
-     *
-     * <p>Callbacks are automatically unregistered when application process goes away
-     *
-     * @param callback user implementation of the {@link AdapterStateCallback}
-     */
-    @RequiresPermission(permission.UWB_PRIVILEGED)
-    public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
-        mAdapterStateListener.unregister(callback);
-    }
-
-    /**
-     * Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
-     * <p>The {@link PersistableBundle} should be parsed using a support library
-     *
-     * <p>Android reserves the '^android.*' namespace</p>
-     *
-     * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
-     */
-    @NonNull
-    @RequiresPermission(permission.UWB_PRIVILEGED)
-    public PersistableBundle getSpecificationInfo() {
-        try {
-            return mUwbAdapter.getSpecificationInfo();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Get the timestamp resolution for events in nanoseconds
-     * <p>This value defines the maximum error of all timestamps for events reported to
-     * {@link RangingSession.Callback}.
-     *
-     * @return the timestamp resolution in nanoseconds
-     */
-    @SuppressLint("MethodNameUnits")
-    @RequiresPermission(permission.UWB_PRIVILEGED)
-    public long elapsedRealtimeResolutionNanos() {
-        try {
-            return mUwbAdapter.getTimestampResolutionNanos();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Open a {@link RangingSession} with the given parameters
-     * <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a
-     * {@link RangingSession} object used to control ranging when the session is successfully
-     * opened.
-     *
-     * <p>If a session cannot be opened, then
-     * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} will be invoked with the
-     * appropriate {@link RangingSession.Callback.Reason}.
-     *
-     * <p>An open {@link RangingSession} will be automatically closed if client application process
-     * dies.
-     *
-     * <p>A UWB support library must be used in order to construct the {@code parameter}
-     * {@link PersistableBundle}.
-     *
-     * @param parameters the parameters that define the ranging session
-     * @param executor {@link Executor} to run callbacks
-     * @param callbacks {@link RangingSession.Callback} to associate with the
-     *                  {@link RangingSession} that is being opened.
-     *
-     * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
-     *         {@link RangingSession} that has been requested through {@link #openRangingSession}
-     *         but has not yet been made available by
-     *         {@link RangingSession.Callback#onOpened(RangingSession)}.
-     */
-    @NonNull
-    @RequiresPermission(allOf = {
-            permission.UWB_PRIVILEGED,
-            permission.UWB_RANGING
-    })
-    public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull RangingSession.Callback callbacks) {
-        return mRangingManager.openSession(
-                mContext.getAttributionSource(), parameters, executor, callbacks);
-    }
-
-    /**
-     * Returns the current enabled/disabled state for UWB.
-     *
-     * Possible values are:
-     * AdapterStateCallback#STATE_DISABLED
-     * AdapterStateCallback#STATE_ENABLED_INACTIVE
-     * AdapterStateCallback#STATE_ENABLED_ACTIVE
-     *
-     * @return value representing current enabled/disabled state for UWB.
-     * @hide
-     */
-    public @AdapterStateCallback.State int getAdapterState() {
-        return mAdapterStateListener.getAdapterState();
-    }
-
-    /**
-     * Disables or enables UWB for a user
-     *
-     * @param enabled value representing intent to disable or enable UWB. If true any subsequent
-     * calls to IUwbAdapter#openRanging will be allowed. If false, all active ranging sessions will
-     * be closed and subsequent calls to IUwbAdapter#openRanging will be disallowed.
-     *
-     * @hide
-     */
-    public void setUwbEnabled(boolean enabled) {
-        mAdapterStateListener.setEnabled(enabled);
-    }
-}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index d23200b..656fdbd 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -151,7 +151,8 @@
             if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId
                     && mHandler.hasAccessibilityCallback(message)) {
                 AccessibilityInteractionClient.getInstanceForThread(
-                        interrogatingTid).setSameThreadMessage(message);
+                        interrogatingTid, /* initializeCache= */true)
+                        .setSameThreadMessage(message);
             } else {
                 // For messages without callback of interrogating client, just handle the
                 // message immediately if this is UI thread.
diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java
index 7023e4b..af76cb9 100644
--- a/core/java/android/view/BatchedInputEventReceiver.java
+++ b/core/java/android/view/BatchedInputEventReceiver.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Handler;
 import android.os.Looper;
 
 /**
@@ -27,6 +28,13 @@
     private Choreographer mChoreographer;
     private boolean mBatchingEnabled;
     private boolean mBatchedInputScheduled;
+    private final Handler mHandler;
+    private final Runnable mConsumeBatchedInputEvents = new Runnable() {
+        @Override
+        public void run() {
+            consumeBatchedInputEvents(-1);
+        }
+    };
 
     @UnsupportedAppUsage
     public BatchedInputEventReceiver(
@@ -34,6 +42,7 @@
         super(inputChannel, looper);
         mChoreographer = choreographer;
         mBatchingEnabled = true;
+        mHandler = new Handler(looper);
     }
 
     @Override
@@ -60,7 +69,7 @@
         mBatchingEnabled = batchingEnabled;
         if (!batchingEnabled) {
             unscheduleBatchedInput();
-            consumeBatchedInputEvents(-1);
+            mHandler.post(mConsumeBatchedInputEvents);
         }
     }
 
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 0257e55..c1a5636 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -39,6 +39,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.DisplayUtils;
 import android.util.Pair;
 import android.util.RotationUtils;
 import android.util.proto.ProtoOutputStream;
@@ -874,38 +875,13 @@
     }
 
     /**
-     * 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 int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
         final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray);
         if (index >= 0 && index < array.length) {
             return array[index];
@@ -920,7 +896,7 @@
      * {@link R.array#config_displayUniqueIdArray} is not set.
      */
     private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) {
-        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
         final String[] array = res.getStringArray(
                 R.array.config_displayCutoutApproximationRectArray);
         if (index >= 0 && index < array.length) {
@@ -939,7 +915,7 @@
      * @hide
      */
     public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) {
-        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
         final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray);
         boolean maskCutout;
         if (index >= 0 && index < array.length()) {
@@ -961,7 +937,7 @@
      * @hide
      */
     public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) {
-        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
         final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray);
         boolean fillCutout;
         if (index >= 0 && index < array.length()) {
@@ -984,7 +960,7 @@
      */
     private static Insets getWaterfallInsets(Resources res, String displayUniqueId) {
         Insets insets;
-        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(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);
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/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 9f63500..ec613ed 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -122,6 +122,29 @@
     public static final int REJECT = 17;
 
     /**
+     * A haptic effect to provide texture while a rotary input device is being scrolled.
+     *
+     * @hide
+     */
+    public static final int ROTARY_SCROLL_TICK = 18;
+
+    /**
+     * A haptic effect to signal that a list element has been focused while scrolling using a rotary
+     * input device.
+     *
+     * @hide
+     */
+    public static final int ROTARY_SCROLL_ITEM_FOCUS = 19;
+
+    /**
+     * A haptic effect to signal reaching the scrolling limits of a list while scrolling using a
+     * rotary input device.
+     *
+     * @hide
+     */
+    public static final int ROTARY_SCROLL_LIMIT = 20;
+
+    /**
      * The phone has booted with safe mode enabled.
      * This is a private constant.  Feel free to renumber as desired.
      * @hide
diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl
index 610e0f8..f95d6b3 100644
--- a/core/java/android/view/IDisplayWindowListener.aidl
+++ b/core/java/android/view/IDisplayWindowListener.aidl
@@ -32,7 +32,8 @@
 oneway interface IDisplayWindowListener {
 
     /**
-     * Called when a display is added to the WM hierarchy.
+     * Called when a new display is added to the WM hierarchy. The existing display ids are returned
+     * when this listener is registered with WM via {@link #registerDisplayWindowListener}.
      */
     void onDisplayAdded(int displayId);
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8c2348c..371d3d0 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -521,9 +521,10 @@
     void unregisterDisplayFoldListener(IDisplayFoldListener listener);
 
     /**
-     * Registers an IDisplayContainerListener
+     * Registers an IDisplayContainerListener, and returns the set of existing display ids. The
+     * listener's onDisplayAdded() will not be called for the displays returned.
      */
-    void registerDisplayWindowListener(IDisplayWindowListener listener);
+    int[] registerDisplayWindowListener(IDisplayWindowListener listener);
 
     /**
      * Unregisters an IDisplayContainerListener.
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/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index bd97ef0..2b579d0 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.Nullable;
+import android.graphics.Matrix;
 import android.graphics.Region;
 import android.gui.TouchOcclusionMode;
 import android.os.IBinder;
@@ -41,6 +42,17 @@
     // channel and the server input channel will both contain this token.
     public IBinder token;
 
+    /**
+     * The {@link IWindow} handle if InputWindowHandle is associated with a window, null otherwise.
+     */
+    @Nullable
+    private IBinder windowToken;
+    /**
+     * Used to cache IWindow from the windowToken so we don't need to convert every time getWindow
+     * is called.
+     */
+    private IWindow window;
+
     // The window name.
     public String name;
 
@@ -116,6 +128,12 @@
      */
     public boolean replaceTouchableRegionWithCrop;
 
+    /**
+     * The transform that should be applied to the Window to get it from screen coordinates to
+     * window coordinates
+     */
+    public Matrix transform;
+
     private native void nativeDispose();
 
     public InputWindowHandle(InputApplicationHandle inputApplicationHandle, int displayId) {
@@ -130,6 +148,9 @@
                         .append(frameRight).append(",").append(frameBottom).append("]")
                 .append(", touchableRegion=").append(touchableRegion)
                 .append(", visible=").append(visible)
+                .append(", scaleFactor=").append(scaleFactor)
+                .append(", transform=").append(transform)
+                .append(", windowToken=").append(windowToken)
                 .toString();
 
     }
@@ -161,4 +182,17 @@
     public void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
         touchableRegionSurfaceControl = new WeakReference<>(bounds);
     }
+
+    public void setWindowToken(IWindow iwindow) {
+        windowToken = iwindow.asBinder();
+        window = iwindow;
+    }
+
+    public IWindow getWindow() {
+        if (window != null) {
+            return window;
+        }
+        window = IWindow.Stub.asInterface(windowToken);
+        return window;
+    }
 }
diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java
index 3431c3e..04bb609 100644
--- a/core/java/android/view/InsetsAnimationControlCallbacks.java
+++ b/core/java/android/view/InsetsAnimationControlCallbacks.java
@@ -20,7 +20,8 @@
 import android.view.WindowInsetsAnimation.Bounds;
 
 /**
- * Provide an interface to let InsetsAnimationControlImpl call back into its owner.
+ * Provide an interface to let InsetsAnimationControlImpl and InsetsResizeAnimationRunner call back
+ * into its owner.
  * @hide
  */
 public interface InsetsAnimationControlCallbacks {
@@ -34,10 +35,9 @@
      *     <li>Dispatch {@link WindowInsetsAnimationControlListener#onReady}</li>
      * </ul>
      */
-    void startAnimation(InsetsAnimationControlImpl controller,
-            WindowInsetsAnimationControlListener listener, int types,
-            WindowInsetsAnimation animation,
-            Bounds bounds);
+    <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+    void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
+            WindowInsetsAnimation animation, Bounds bounds);
 
     /**
      * Schedule the apply by posting the animation callback.
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 17b3020..7d8d653 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -69,7 +69,7 @@
  * @hide
  */
 @VisibleForTesting
-public class InsetsAnimationControlImpl implements WindowInsetsAnimationController,
+public class InsetsAnimationControlImpl implements InternalInsetsAnimationController,
         InsetsAnimationControlRunner {
 
     private static final String TAG = "InsetsAnimationCtrlImpl";
@@ -105,7 +105,7 @@
     private float mCurrentAlpha = 1.0f;
     private float mPendingAlpha = 1.0f;
     @VisibleForTesting(visibility = PACKAGE)
-    public boolean mReadyDispatched;
+    private boolean mReadyDispatched;
     private Boolean mPerceptible;
 
     @VisibleForTesting
@@ -170,6 +170,11 @@
     }
 
     @Override
+    public void setReadyDispatched(boolean dispatched) {
+        mReadyDispatched = dispatched;
+    }
+
+    @Override
     public Insets getHiddenStateInsets() {
         return mHiddenInsets;
     }
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 691e638..fc97541 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -54,8 +54,8 @@
 
         @Override
         @UiThread
-        public void startAnimation(InsetsAnimationControlImpl controller,
-                WindowInsetsAnimationControlListener listener, int types,
+        public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+        void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
                 WindowInsetsAnimation animation, Bounds bounds) {
             // Animation will be started in constructor already.
         }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 2ed705a..1dd5a1b 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -205,6 +205,9 @@
     private static final int ANIMATION_DURATION_FADE_IN_MS = 500;
     private static final int ANIMATION_DURATION_FADE_OUT_MS = 1500;
 
+    /** Visible for WindowManagerWrapper */
+    public static final int ANIMATION_DURATION_RESIZE = 300;
+
     private static final int ANIMATION_DELAY_DIM_MS = 500;
 
     private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
@@ -235,6 +238,9 @@
     private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
             new PathInterpolator(0.4f, 0f, 1f, 1f);
 
+    /** Visible for WindowManagerWrapper */
+    public static final Interpolator RESIZE_INTERPOLATOR = new LinearInterpolator();
+
     /** The amount IME will move up/down when animating in floating mode. */
     private static final int FLOATING_IME_BOTTOM_INSET_DP = -80;
 
@@ -288,9 +294,13 @@
     @VisibleForTesting
     public static final int ANIMATION_TYPE_USER = 2;
 
+    /** Running animation will resize insets */
+    @VisibleForTesting
+    public static final int ANIMATION_TYPE_RESIZE = 3;
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
-            ANIMATION_TYPE_USER})
+            ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE})
     @interface AnimationType {
     }
 
@@ -320,7 +330,7 @@
         private final boolean mDisable;
         private final int mFloatingImeBottomInset;
 
-        private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+        private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
                 new ThreadLocal<AnimationHandler>() {
             @Override
             protected AnimationHandler initialValue() {
@@ -550,7 +560,6 @@
 
     private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
     private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
-    private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
     private final ArraySet<InsetsSourceConsumer> mRequestedVisibilityChanged = new ArraySet<>();
     private WindowInsets mLastInsets;
 
@@ -570,7 +579,7 @@
     private int mCaptionInsetsHeight = 0;
     private boolean mAnimationsDisabled;
 
-    private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
+    private final Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
     private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
             = new ArrayList<>();
 
@@ -580,7 +589,7 @@
     /** Set of inset types which cannot be controlled by the user animation */
     private @InsetsType int mDisabledUserAnimationInsetsTypes;
 
-    private Runnable mInvokeControllableInsetsChangedListeners =
+    private final Runnable mInvokeControllableInsetsChangedListeners =
             this::invokeControllableInsetsChangedListeners;
 
     public InsetsController(Host host) {
@@ -608,23 +617,23 @@
             }
 
             final List<WindowInsetsAnimation> runningAnimations = new ArrayList<>();
+            final List<WindowInsetsAnimation> finishedAnimations = new ArrayList<>();
             final InsetsState state = new InsetsState(mState, true /* copySources */);
             for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                 RunningAnimation runningAnimation = mRunningAnimations.get(i);
                 if (DEBUG) Log.d(TAG, "Running animation type: " + runningAnimation.type);
-                InsetsAnimationControlRunner runner = runningAnimation.runner;
-                if (runner instanceof InsetsAnimationControlImpl) {
-                    InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
+                final InsetsAnimationControlRunner runner = runningAnimation.runner;
+                if (runner instanceof WindowInsetsAnimationController) {
 
                     // Keep track of running animation to be dispatched. Aggregate it here such that
                     // if it gets finished within applyChangeInsets we still dispatch it to
                     // onProgress.
                     if (runningAnimation.startDispatched) {
-                        runningAnimations.add(control.getAnimation());
+                        runningAnimations.add(runner.getAnimation());
                     }
 
-                    if (control.applyChangeInsets(state)) {
-                        mTmpFinishedControls.add(control);
+                    if (((InternalInsetsAnimationController) runner).applyChangeInsets(state)) {
+                        finishedAnimations.add(runner.getAnimation());
                     }
                 }
             }
@@ -642,10 +651,9 @@
                 }
             }
 
-            for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
-                dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
+            for (int i = finishedAnimations.size() - 1; i >= 0; i--) {
+                dispatchAnimationEnd(finishedAnimations.get(i));
             }
-            mTmpFinishedControls.clear();
         };
     }
 
@@ -691,15 +699,13 @@
                 true /* excludeInvisibleIme */)) {
             if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
             mHost.notifyInsetsChanged();
+            startResizingAnimationIfNeeded(lastState);
         }
         return true;
     }
 
     private void updateState(InsetsState newState) {
-        mState.setDisplayFrame(newState.getDisplayFrame());
-        mState.setDisplayCutout(newState.getDisplayCutout());
-        mState.setRoundedCorners(newState.getRoundedCorners());
-        mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds());
+        mState.set(newState, 0 /* types */);
         @InsetsType int disabledUserAnimationTypes = 0;
         @InsetsType int[] cancelledUserAnimationTypes = {0};
         for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
@@ -764,6 +770,39 @@
         return false;
     }
 
+    private void startResizingAnimationIfNeeded(InsetsState fromState) {
+        if (!fromState.getDisplayFrame().equals(mState.getDisplayFrame())) {
+            return;
+        }
+        @InsetsType int types = 0;
+        InsetsState toState = null;
+        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(Type.systemBars());
+        for (int i = internalTypes.size() - 1; i >= 0; i--) {
+            final @InternalInsetsType int type = internalTypes.valueAt(i);
+            final InsetsSource fromSource = fromState.peekSource(type);
+            final InsetsSource toSource = mState.peekSource(type);
+            if (fromSource != null && toSource != null
+                    && fromSource.isVisible() && toSource.isVisible()
+                    && !fromSource.getFrame().equals(toSource.getFrame())
+                    && (Rect.intersects(mFrame, fromSource.getFrame())
+                            || Rect.intersects(mFrame, toSource.getFrame()))) {
+                types |= InsetsState.toPublicType(toSource.getType());
+                if (toState == null) {
+                    toState = new InsetsState();
+                }
+                toState.addSource(new InsetsSource(toSource));
+            }
+        }
+        if (types == 0) {
+            return;
+        }
+        cancelExistingControllers(types);
+        final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
+                mFrame, fromState, toState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, types,
+                this);
+        mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
+    }
+
     /**
      * @see InsetsState#calculateInsets
      */
@@ -785,7 +824,7 @@
     /**
      * @see InsetsState#calculateVisibleInsets(Rect, int)
      */
-    public Rect calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
+    public Insets calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
         return mState.calculateVisibleInsets(mFrame, softInputMode);
     }
 
@@ -1474,12 +1513,12 @@
 
     @VisibleForTesting
     @Override
-    public void startAnimation(InsetsAnimationControlImpl controller,
-            WindowInsetsAnimationControlListener listener, int types,
+    public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+    void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
             WindowInsetsAnimation animation, Bounds bounds) {
         mHost.dispatchWindowInsetsAnimationPrepare(animation);
         mHost.addOnPreDrawRunnable(() -> {
-            if (controller.isCancelled()) {
+            if (runner.isCancelled()) {
                 if (WARN) Log.w(TAG, "startAnimation canceled before preDraw");
                 return;
             }
@@ -1487,15 +1526,15 @@
                     "InsetsAnimation: " + WindowInsets.Type.toString(types), types);
             for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                 RunningAnimation runningAnimation = mRunningAnimations.get(i);
-                if (runningAnimation.runner == controller) {
+                if (runningAnimation.runner == runner) {
                     runningAnimation.startDispatched = true;
                 }
             }
             Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
             mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
             mStartingAnimation = true;
-            controller.mReadyDispatched = true;
-            listener.onReady(controller, types);
+            runner.setReadyDispatched(true);
+            listener.onReady(runner, types);
             mStartingAnimation = false;
         });
     }
diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java
new file mode 100644
index 0000000..e1352dd
--- /dev/null
+++ b/core/java/android/view/InsetsResizeAnimationRunner.java
@@ -0,0 +1,235 @@
+/*
+ * 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.view;
+
+import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED;
+import static android.view.InsetsAnimationControlImplProto.IS_FINISHED;
+import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
+import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
+import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
+import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
+import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowInsetsAnimation.Bounds;
+import android.view.animation.Interpolator;
+
+/**
+ * Runs a fake animation of resizing insets to produce insets animation callbacks.
+ * @hide
+ */
+public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner,
+        InternalInsetsAnimationController, WindowInsetsAnimationControlListener {
+
+    private final InsetsState mFromState;
+    private final InsetsState mToState;
+    private final @InsetsType int mTypes;
+    private final WindowInsetsAnimation mAnimation;
+    private final InsetsAnimationControlCallbacks mController;
+    private ValueAnimator mAnimator;
+    private boolean mCancelled;
+    private boolean mFinished;
+
+    public InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState,
+            Interpolator interpolator, long duration, @InsetsType int types,
+            InsetsAnimationControlCallbacks controller) {
+        mFromState = fromState;
+        mToState = toState;
+        mTypes = types;
+        mController = controller;
+        mAnimation = new WindowInsetsAnimation(types, interpolator, duration);
+        mAnimation.setAlpha(1f);
+        final Insets fromInsets = fromState.calculateInsets(
+                frame, types, false /* ignoreVisibility */);
+        final Insets toInsets = toState.calculateInsets(
+                frame, types, false /* ignoreVisibility */);
+        controller.startAnimation(this, this, types, mAnimation,
+                new Bounds(Insets.min(fromInsets, toInsets), Insets.max(fromInsets, toInsets)));
+    }
+
+    @Override
+    public int getTypes() {
+        return mTypes;
+    }
+
+    @Override
+    public int getControllingTypes() {
+        return mTypes;
+    }
+
+    @Override
+    public WindowInsetsAnimation getAnimation() {
+        return mAnimation;
+    }
+
+    @Override
+    public int getAnimationType() {
+        return ANIMATION_TYPE_RESIZE;
+    }
+
+    @Override
+    public void cancel() {
+        if (mCancelled || mFinished) {
+            return;
+        }
+        mCancelled = true;
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return mCancelled;
+    }
+
+    @Override
+    public void onReady(WindowInsetsAnimationController controller, int types) {
+        if (mCancelled) {
+            return;
+        }
+        mAnimator = ValueAnimator.ofFloat(0f, 1f);
+        mAnimator.setDuration(mAnimation.getDurationMillis());
+        mAnimator.addUpdateListener(animation -> {
+            mAnimation.setFraction(animation.getAnimatedFraction());
+            mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
+        });
+        mAnimator.addListener(new AnimatorListenerAdapter() {
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mFinished = true;
+                mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
+            }
+        });
+        mAnimator.start();
+    }
+
+    @Override
+    public boolean applyChangeInsets(InsetsState outState) {
+        final float fraction = mAnimation.getInterpolatedFraction();
+        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
+            final InsetsSource fromSource = mFromState.peekSource(type);
+            final InsetsSource toSource = mToState.peekSource(type);
+            if (fromSource == null || toSource == null) {
+                continue;
+            }
+            final Rect fromFrame = fromSource.getFrame();
+            final Rect toFrame = toSource.getFrame();
+            final Rect frame = new Rect(
+                    (int) (fromFrame.left + fraction * (toFrame.left - fromFrame.left)),
+                    (int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)),
+                    (int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)),
+                    (int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom)));
+            final InsetsSource source = new InsetsSource(type);
+            source.setFrame(frame);
+            source.setVisible(toSource.isVisible());
+            outState.addSource(source);
+        }
+        if (mFinished) {
+            mController.notifyFinished(this, true /* shown */);
+        }
+        return mFinished;
+    }
+
+    @Override
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(IS_CANCELLED, mCancelled);
+        proto.write(IS_FINISHED, mFinished);
+        proto.write(TMP_MATRIX, "null");
+        proto.write(PENDING_INSETS, "null");
+        proto.write(PENDING_FRACTION, mAnimation.getInterpolatedFraction());
+        proto.write(SHOWN_ON_FINISH, true);
+        proto.write(CURRENT_ALPHA, 1f);
+        proto.write(PENDING_ALPHA, 1f);
+        proto.end(token);
+    }
+
+    @Override
+    public Insets getHiddenStateInsets() {
+        return Insets.NONE;
+    }
+
+    @Override
+    public Insets getShownStateInsets() {
+        return Insets.NONE;
+    }
+
+    @Override
+    public Insets getCurrentInsets() {
+        return Insets.NONE;
+    }
+
+    @Override
+    public float getCurrentFraction() {
+        return 0;
+    }
+
+    @Override
+    public float getCurrentAlpha() {
+        return 0;
+    }
+
+    @Override
+    public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
+    }
+
+    @Override
+    public void finish(boolean shown) {
+    }
+
+    @Override
+    public boolean isFinished() {
+        return false;
+    }
+
+    @Override
+    public void notifyControlRevoked(int types) {
+    }
+
+    @Override
+    public void updateSurfacePosition(SparseArray<InsetsSourceControl> controls) {
+    }
+
+    @Override
+    public boolean hasZeroInsetsIme() {
+        return false;
+    }
+
+    @Override
+    public void setReadyDispatched(boolean dispatched) {
+    }
+
+    @Override
+    public void onFinished(WindowInsetsAnimationController controller) {
+    }
+
+    @Override
+    public void onCancelled(WindowInsetsAnimationController controller) {
+    }
+}
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 1506ee4..9d98a3e 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -185,6 +185,15 @@
         return result;
     }
 
+    @Override
+    public String toString() {
+        return "InsetsSourceControl: {"
+                + "type=" + InsetsState.typeToString(mType)
+                + ", mSurfacePosition=" + mSurfacePosition
+                + ", mInsetsHint=" + mInsetsHint
+                + "}";
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index f4444a1..75b69cb 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -301,7 +301,7 @@
         return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
     }
 
-    public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
+    public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
         Insets insets = Insets.NONE;
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources[type];
@@ -314,10 +314,10 @@
             }
             insets = Insets.max(source.calculateInsets(frame, ignoreVisibility), insets);
         }
-        return insets.toRect();
+        return insets;
     }
 
-    public Rect calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
+    public Insets calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
         Insets insets = Insets.NONE;
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources[type];
@@ -332,7 +332,7 @@
             }
             insets = Insets.max(source.calculateVisibleInsets(frame), insets);
         }
-        return insets.toRect();
+        return insets;
     }
 
     /**
diff --git a/core/java/android/view/InternalInsetsAnimationController.java b/core/java/android/view/InternalInsetsAnimationController.java
new file mode 100644
index 0000000..d7f3e20
--- /dev/null
+++ b/core/java/android/view/InternalInsetsAnimationController.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 android.view;
+
+/**
+ * An internal interface which provides methods that will be only used by the framework.
+ * @hide
+ */
+public interface InternalInsetsAnimationController extends WindowInsetsAnimationController {
+
+    /**
+     * Flags whether {@link WindowInsetsAnimationControlListener#onReady(
+     * WindowInsetsAnimationController, int)} has been invoked.
+     * @hide
+     */
+    void setReadyDispatched(boolean dispatched);
+
+    /**
+     * Returns the {@link InsetsState} based on the current animation progress.
+     *
+     * @param outState the insets state which matches the current animation progress.
+     * @return {@code true} if the animation has been finished; {@code false} otherwise.
+     * @hide
+     */
+    boolean applyChangeInsets(InsetsState outState);
+}
+
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index cda9b23..d12ed8f 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -31,6 +31,8 @@
 import android.util.SparseIntArray;
 import android.view.KeyCharacterMap.KeyData;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Object used to report key and button events.
  * <p>
@@ -1298,9 +1300,16 @@
     private int mRepeatCount;
     @UnsupportedAppUsage
     private int mFlags;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    /**
+     * The time when the key initially was pressed, in nanoseconds. Only millisecond precision is
+     * exposed as public api, so this must always be converted to / from milliseconds when used.
+     */
     private long mDownTime;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    /**
+     * The time when the current key event occurred. If mAction is ACTION_DOWN, then this is equal
+     * to mDownTime. Only millisecond precision is exposed as public api, so this must always be
+     * converted to / from milliseconds when used.
+     */
     private long mEventTime;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private String mCharacters;
@@ -1400,8 +1409,8 @@
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat) {
         mId = nativeNextId();
-        mDownTime = downTime;
-        mEventTime = eventTime;
+        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
@@ -1425,8 +1434,8 @@
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState) {
         mId = nativeNextId();
-        mDownTime = downTime;
-        mEventTime = eventTime;
+        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
@@ -1454,8 +1463,8 @@
                     int code, int repeat, int metaState,
                     int deviceId, int scancode) {
         mId = nativeNextId();
-        mDownTime = downTime;
-        mEventTime = eventTime;
+        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
@@ -1485,8 +1494,8 @@
                     int code, int repeat, int metaState,
                     int deviceId, int scancode, int flags) {
         mId = nativeNextId();
-        mDownTime = downTime;
-        mEventTime = eventTime;
+        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
@@ -1518,8 +1527,8 @@
                     int code, int repeat, int metaState,
                     int deviceId, int scancode, int flags, int source) {
         mId = nativeNextId();
-        mDownTime = downTime;
-        mEventTime = eventTime;
+        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
@@ -1545,8 +1554,8 @@
      */
     public KeyEvent(long time, String characters, int deviceId, int flags) {
         mId = nativeNextId();
-        mDownTime = time;
-        mEventTime = time;
+        mDownTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS);
         mCharacters = characters;
         mAction = ACTION_MULTIPLE;
         mKeyCode = KEYCODE_UNKNOWN;
@@ -1592,7 +1601,7 @@
     public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
         mId = nativeNextId();  // Not an exact copy so assign a new ID.
         mDownTime = origEvent.mDownTime;
-        mEventTime = eventTime;
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         mAction = origEvent.mAction;
         mKeyCode = origEvent.mKeyCode;
         mRepeatCount = newRepeat;
@@ -1626,14 +1635,14 @@
      *
      * @hide
      */
-    public static KeyEvent obtain(int id, long downTime, long eventTime, int action,
+    private static KeyEvent obtain(int id, long downTimeNanos, long eventTimeNanos, int action,
             int code, int repeat, int metaState,
             int deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac,
             String characters) {
         KeyEvent ev = obtain();
         ev.mId = id;
-        ev.mDownTime = downTime;
-        ev.mEventTime = eventTime;
+        ev.mDownTime = downTimeNanos;
+        ev.mEventTime = eventTimeNanos;
         ev.mAction = action;
         ev.mKeyCode = code;
         ev.mRepeatCount = repeat;
@@ -1656,6 +1665,8 @@
     public static KeyEvent obtain(long downTime, long eventTime, int action,
             int code, int repeat, int metaState,
             int deviceId, int scanCode, int flags, int source, int displayId, String characters) {
+        downTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        eventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState,
                 deviceId, scanCode, flags, source, displayId, null /* hmac */, characters);
     }
@@ -1669,6 +1680,8 @@
     public static KeyEvent obtain(long downTime, long eventTime, int action,
             int code, int repeat, int metaState,
             int deviceId, int scancode, int flags, int source, String characters) {
+        // Do not convert downTime and eventTime here. We are calling the obtain method above,
+        // which will do the conversion. Just specify INVALID_DISPLAY and forward the request.
         return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode,
                 flags, source, INVALID_DISPLAY, characters);
     }
@@ -1768,7 +1781,7 @@
             int newRepeat, int newFlags) {
         KeyEvent ret = new KeyEvent(event);
         ret.mId = nativeNextId();  // Not an exact copy so assign a new ID.
-        ret.mEventTime = eventTime;
+        ret.mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
         ret.mRepeatCount = newRepeat;
         ret.mFlags = newFlags;
         return ret;
@@ -2617,8 +2630,8 @@
      * @hide
      */
     public final void setTime(long downTime, long eventTime) {
-        mDownTime = downTime;
-        mEventTime = eventTime;
+        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
+        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
     }
 
     /**
@@ -2633,7 +2646,7 @@
      * {@link android.os.SystemClock#uptimeMillis} time base
      */
     public final long getDownTime() {
-        return mDownTime;
+        return TimeUnit.MILLISECONDS.convert(mDownTime, TimeUnit.NANOSECONDS);
     }
 
     /**
@@ -2645,7 +2658,7 @@
      */
     @Override
     public final long getEventTime() {
-        return mEventTime;
+        return TimeUnit.MILLISECONDS.convert(mEventTime, TimeUnit.NANOSECONDS);
     }
 
     /**
@@ -2664,7 +2677,7 @@
      */
     @Override
     public final long getEventTimeNano() {
-        return mEventTime * 1000000L;
+        return mEventTime;
     }
 
     /**
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index bd68401..3f71d4d 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -233,7 +233,7 @@
         this.clipRect = new Rect(clipRect);
         this.contentInsets = new Rect(contentInsets);
         this.prefixOrderIndex = prefixOrderIndex;
-        this.position = new Point(position);
+        this.position = position == null ? new Point() : new Point(position);
         this.localBounds = new Rect(localBounds);
         this.sourceContainerBounds = new Rect(screenSpaceBounds);
         this.screenSpaceBounds = new Rect(screenSpaceBounds);
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index 623d969..6079d8e 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -27,9 +27,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Point;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.DisplayUtils;
 import android.util.Pair;
 import android.view.RoundedCorner.Position;
 
@@ -94,8 +96,8 @@
      * @android:dimen/rounded_corner_radius_top and @android:dimen/rounded_corner_radius_bottom
      */
     public static RoundedCorners fromResources(
-            Resources res, int displayWidth, int displayHeight) {
-        return fromRadii(loadRoundedCornerRadii(res), displayWidth, displayHeight);
+            Resources res, String displayUniqueId, int displayWidth, int displayHeight) {
+        return fromRadii(loadRoundedCornerRadii(res, displayUniqueId), displayWidth, displayHeight);
     }
 
     /**
@@ -140,14 +142,16 @@
      * Loads the rounded corner radii from resources.
      *
      * @param res
+     * @param displayUniqueId the display unique id.
      * @return a Pair of radius. The first is the top rounded corner radius and second is the
      * bottom corner radius.
      */
     @Nullable
-    private static Pair<Integer, Integer> loadRoundedCornerRadii(Resources res) {
-        final int radiusDefault = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
-        final int radiusTop = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top);
-        final int radiusBottom = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom);
+    private static Pair<Integer, Integer> loadRoundedCornerRadii(
+            Resources res, String displayUniqueId) {
+        final int radiusDefault = getRoundedCornerRadius(res, displayUniqueId);
+        final int radiusTop = getRoundedCornerTopRadius(res, displayUniqueId);
+        final int radiusBottom = getRoundedCornerBottomRadius(res, displayUniqueId);
         if (radiusDefault == 0 && radiusTop == 0 && radiusBottom == 0) {
             return null;
         }
@@ -158,6 +162,164 @@
     }
 
     /**
+     * Gets the default rounded corner radius of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default dimen{@link R.dimen#rounded_corner_radius} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static int getRoundedCornerRadius(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerRadiusArray);
+        int radius;
+        if (index >= 0 && index < array.length()) {
+            radius = array.getDimensionPixelSize(index, 0);
+        } else {
+            radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
+        }
+        array.recycle();
+        return radius;
+    }
+
+    /**
+     * Gets the top rounded corner radius of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default dimen{@link R.dimen#rounded_corner_radius_top} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static int getRoundedCornerTopRadius(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopRadiusArray);
+        int radius;
+        if (index >= 0 && index < array.length()) {
+            radius = array.getDimensionPixelSize(index, 0);
+        } else {
+            radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top);
+        }
+        array.recycle();
+        return radius;
+    }
+
+    /**
+     * Gets the bottom rounded corner radius of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default dimen{@link R.dimen#rounded_corner_radius_bottom} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static int getRoundedCornerBottomRadius(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(
+                R.array.config_roundedCornerBottomRadiusArray);
+        int radius;
+        if (index >= 0 && index < array.length()) {
+            radius = array.getDimensionPixelSize(index, 0);
+        } else {
+            radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom);
+        }
+        array.recycle();
+        return radius;
+    }
+
+    /**
+     * Gets the rounded corner radius adjustment of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default dimen{@link R.dimen#rounded_corner_radius_adjustment} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static int getRoundedCornerRadiusAdjustment(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(
+                R.array.config_roundedCornerRadiusAdjustmentArray);
+        int radius;
+        if (index >= 0 && index < array.length()) {
+            radius = array.getDimensionPixelSize(index, 0);
+        } else {
+            radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_adjustment);
+        }
+        array.recycle();
+        return radius;
+    }
+
+    /**
+     * Gets the rounded corner top radius adjustment of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default dimen{@link R.dimen#rounded_corner_radius_top_adjustment} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static int getRoundedCornerRadiusTopAdjustment(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(
+                R.array.config_roundedCornerTopRadiusAdjustmentArray);
+        int radius;
+        if (index >= 0 && index < array.length()) {
+            radius = array.getDimensionPixelSize(index, 0);
+        } else {
+            radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top_adjustment);
+        }
+        array.recycle();
+        return radius;
+    }
+
+    /**
+     * Gets the rounded corner bottom radius adjustment of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default dimen{@link R.dimen#rounded_corner_radius_bottom_adjustment} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static int getRoundedCornerRadiusBottomAdjustment(
+            Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(
+                R.array.config_roundedCornerBottomRadiusAdjustmentArray);
+        int radius;
+        if (index >= 0 && index < array.length()) {
+            radius = array.getDimensionPixelSize(index, 0);
+        } else {
+            radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom_adjustment);
+        }
+        array.recycle();
+        return radius;
+    }
+
+    /**
+     * Gets whether a built-in display is round.
+     *
+     * Loads the default config{@link R.bool#config_mainBuiltInDisplayIsRound} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static boolean getBuiltInDisplayIsRound(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray);
+        boolean isRound;
+        if (index >= 0 && index < array.length()) {
+            isRound = array.getBoolean(index, false);
+        } else {
+            isRound = res.getBoolean(R.bool.config_mainBuiltInDisplayIsRound);
+        }
+        array.recycle();
+        return isRound;
+    }
+
+    /**
      * Insets the reference frame of the rounded corners.
      *
      * @return a copy of this instance which has been inset
diff --git a/core/java/android/view/ScrollCaptureResponse.java b/core/java/android/view/ScrollCaptureResponse.java
index 8808827..758f9ab 100644
--- a/core/java/android/view/ScrollCaptureResponse.java
+++ b/core/java/android/view/ScrollCaptureResponse.java
@@ -53,6 +53,10 @@
     @Nullable
     private String mWindowTitle = null;
 
+    /** The package which owns the window. */
+    @Nullable
+    private String mPackageName = null;
+
     /** Carries additional logging and debugging information when enabled. */
     @NonNull
     @DataClass.PluralOf("message")
@@ -77,7 +81,7 @@
 
 
 
-    // Code below generated by codegen v1.0.22.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -97,6 +101,7 @@
             @Nullable Rect windowBounds,
             @Nullable Rect boundsInWindow,
             @Nullable String windowTitle,
+            @Nullable String packageName,
             @NonNull ArrayList<String> messages) {
         this.mDescription = description;
         com.android.internal.util.AnnotationValidations.validate(
@@ -105,6 +110,7 @@
         this.mWindowBounds = windowBounds;
         this.mBoundsInWindow = boundsInWindow;
         this.mWindowTitle = windowTitle;
+        this.mPackageName = packageName;
         this.mMessages = messages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessages);
@@ -153,6 +159,14 @@
     }
 
     /**
+     * The package name of the process the window is owned by.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
      * Carries additional logging and debugging information when enabled.
      */
     @DataClass.Generated.Member
@@ -172,6 +186,7 @@
                 "windowBounds = " + mWindowBounds + ", " +
                 "boundsInWindow = " + mBoundsInWindow + ", " +
                 "windowTitle = " + mWindowTitle + ", " +
+                "packageName = " + mPackageName + ", " +
                 "messages = " + mMessages +
         " }";
     }
@@ -187,12 +202,14 @@
         if (mWindowBounds != null) flg |= 0x4;
         if (mBoundsInWindow != null) flg |= 0x8;
         if (mWindowTitle != null) flg |= 0x10;
+        if (mPackageName != null) flg |= 0x20;
         dest.writeByte(flg);
         dest.writeString(mDescription);
         if (mConnection != null) dest.writeStrongInterface(mConnection);
         if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
         if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
         if (mWindowTitle != null) dest.writeString(mWindowTitle);
+        if (mPackageName != null) dest.writeString(mPackageName);
         dest.writeStringList(mMessages);
     }
 
@@ -213,6 +230,7 @@
         Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
         Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
         String windowTitle = (flg & 0x10) == 0 ? null : in.readString();
+        String packageName = (flg & 0x20) == 0 ? null : in.readString();
         ArrayList<String> messages = new ArrayList<>();
         in.readStringList(messages);
 
@@ -223,6 +241,7 @@
         this.mWindowBounds = windowBounds;
         this.mBoundsInWindow = boundsInWindow;
         this.mWindowTitle = windowTitle;
+        this.mPackageName = packageName;
         this.mMessages = messages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessages);
@@ -256,6 +275,7 @@
         private @Nullable Rect mWindowBounds;
         private @Nullable Rect mBoundsInWindow;
         private @Nullable String mWindowTitle;
+        private @Nullable String mPackageName;
         private @NonNull ArrayList<String> mMessages;
 
         private long mBuilderFieldsSet = 0L;
@@ -319,12 +339,23 @@
         }
 
         /**
+         * The package name of the process the window is owned by.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setPackageName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mPackageName = value;
+            return this;
+        }
+
+        /**
          * Carries additional logging and debugging information when enabled.
          */
         @DataClass.Generated.Member
         public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x20;
+            mBuilderFieldsSet |= 0x40;
             mMessages = value;
             return this;
         }
@@ -340,7 +371,7 @@
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull ScrollCaptureResponse build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x40; // Mark builder used
+            mBuilderFieldsSet |= 0x80; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mDescription = "";
@@ -358,6 +389,9 @@
                 mWindowTitle = null;
             }
             if ((mBuilderFieldsSet & 0x20) == 0) {
+                mPackageName = null;
+            }
+            if ((mBuilderFieldsSet & 0x40) == 0) {
                 mMessages = new ArrayList<>();
             }
             ScrollCaptureResponse o = new ScrollCaptureResponse(
@@ -366,12 +400,13 @@
                     mWindowBounds,
                     mBoundsInWindow,
                     mWindowTitle,
+                    mPackageName,
                     mMessages);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x40) != 0) {
+            if ((mBuilderFieldsSet & 0x80) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -379,10 +414,10 @@
     }
 
     @DataClass.Generated(
-            time = 1614833185795L,
-            codegenVersion = "1.0.22",
+            time = 1628630366187L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java",
-            inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic  boolean isConnected()\npublic  void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic  boolean isConnected()\npublic  void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ff2d2eb..904aa73 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;
@@ -98,6 +99,7 @@
 
     private static native int nativeSetFrameRate(
             long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
+    private static native void nativeDestroy(long nativeObject);
 
     public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
@@ -339,6 +341,9 @@
      */
     @UnsupportedAppUsage
     public void destroy() {
+        if (mNativeObject != 0) {
+            nativeDestroy(mNativeObject);
+        }
         release();
     }
 
@@ -408,6 +413,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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index d6186d7..9972eba 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -23,6 +23,7 @@
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
 import static android.view.SurfaceControlProto.HASH_CODE;
+import static android.view.SurfaceControlProto.LAYER_ID;
 import static android.view.SurfaceControlProto.NAME;
 
 import android.annotation.FloatRange;
@@ -239,6 +240,7 @@
     private static native int nativeGetGPUContextPriority();
     private static native void nativeSetTransformHint(long nativeObject, int transformHint);
     private static native int nativeGetTransformHint(long nativeObject);
+    private static native int nativeGetLayerId(long nativeObject);
 
     @Nullable
     @GuardedBy("mLock")
@@ -354,8 +356,6 @@
     @GuardedBy("mLock")
     private int mHeight;
 
-    private int mTransformHint;
-
     private WeakReference<View> mLocalOwnerView;
 
     static GlobalTransactionWrapper sGlobalTransaction;
@@ -1538,6 +1538,7 @@
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
         proto.write(NAME, mName);
+        proto.write(LAYER_ID, getLayerId());
         proto.end(token);
     }
 
@@ -3652,4 +3653,15 @@
     public void setTransformHint(@Surface.Rotation int transformHint) {
         nativeSetTransformHint(mNativeObject, transformHint);
     }
+
+    /**
+     * @hide
+     */
+    public int getLayerId() {
+        if (mNativeObject != 0) {
+            return nativeGetLayerId(mNativeObject);
+        }
+
+        return -1;
+    }
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 48ef27f..ddc532c 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;
@@ -912,7 +903,7 @@
         mSurfaceAlpha = 1f;
 
         synchronized (mSurfaceControlLock) {
-            mSurface.release();
+            mSurface.destroy();
             if (mBlastBufferQueue != null) {
                 mBlastBufferQueue.destroy();
                 mBlastBufferQueue = null;
@@ -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();
 
@@ -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;
@@ -1850,10 +1889,12 @@
     public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
         final SurfaceControl lastSc = mSurfacePackage != null ?
                 mSurfacePackage.getSurfaceControl() : null;
-        if (mSurfaceControl != null && lastSc != null) {
-            mTmpTransaction.reparent(lastSc, null).apply();
-            mSurfacePackage.release();
-        } else if (mSurfaceControl != null) {
+        if (mSurfaceControl != null) {
+            if (lastSc != null) {
+                mTmpTransaction.reparent(lastSc, null);
+                mSurfacePackage.release();
+            }
+
             reparentSurfacePackage(mTmpTransaction, p);
             mTmpTransaction.apply();
         }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index d839e35..bee0709 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.BLASTBufferQueue;
 import android.graphics.FrameInfo;
 import android.graphics.HardwareRenderer;
 import android.graphics.Picture;
@@ -257,6 +258,76 @@
     private boolean mEnabled;
     private boolean mRequested = true;
 
+    /**
+     * This child class exists to break ownership cycles. ViewRootImpl owns a ThreadedRenderer
+     * which owns a WebViewOverlayProvider. WebViewOverlayProvider will in turn be set as
+     * the listener for HardwareRenderer callbacks. By keeping this a child class, there are
+     * no cycles in the chain. The ThreadedRenderer will remain GC-able if any callbacks are
+     * still outstanding, which will in turn release any JNI references to WebViewOverlayProvider.
+     */
+    private static final class WebViewOverlayProvider implements
+            PrepareSurfaceControlForWebviewCallback, ASurfaceTransactionCallback {
+        private static final boolean sOverlaysAreEnabled =
+                HardwareRenderer.isWebViewOverlaysEnabled();
+        private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+        private boolean mHasWebViewOverlays = false;
+        private BLASTBufferQueue mBLASTBufferQueue;
+        private SurfaceControl mSurfaceControl;
+
+        public boolean setSurfaceControlOpaque(boolean opaque) {
+            synchronized (this) {
+                if (mHasWebViewOverlays) return false;
+                mTransaction.setOpaque(mSurfaceControl, opaque).apply();
+            }
+            return opaque;
+        }
+
+        public boolean shouldEnableOverlaySupport() {
+            return sOverlaysAreEnabled && mSurfaceControl != null && mBLASTBufferQueue != null;
+        }
+
+        public void setSurfaceControl(SurfaceControl surfaceControl) {
+            synchronized (this) {
+                mSurfaceControl = surfaceControl;
+                if (mSurfaceControl != null && mHasWebViewOverlays) {
+                    mTransaction.setOpaque(surfaceControl, false).apply();
+                }
+            }
+        }
+
+        public void setBLASTBufferQueue(BLASTBufferQueue bufferQueue) {
+            synchronized (this) {
+                mBLASTBufferQueue = bufferQueue;
+            }
+        }
+
+        @Override
+        public void prepare() {
+            synchronized (this) {
+                mHasWebViewOverlays = true;
+                if (mSurfaceControl != null) {
+                    mTransaction.setOpaque(mSurfaceControl, false).apply();
+                }
+            }
+        }
+
+        @Override
+        public boolean onMergeTransaction(long nativeTransactionObj,
+                long aSurfaceControlNativeObj, long frameNr) {
+            synchronized (this) {
+                if (mBLASTBufferQueue == null) {
+                    return false;
+                } else {
+                    mBLASTBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr);
+                    return true;
+                }
+            }
+        }
+    }
+
+    private final WebViewOverlayProvider mWebViewOverlayProvider = new WebViewOverlayProvider();
+    private boolean mWebViewOverlaysEnabled = false;
+
     @Nullable
     private ArrayList<FrameDrawingCallback> mNextRtFrameCallbacks;
 
@@ -455,6 +526,56 @@
     }
 
     /**
+     * Whether or not the renderer owns the SurfaceControl's opacity. If true, use
+     * {@link #setSurfaceControlOpaque(boolean)} to update the opacity
+     */
+    public boolean rendererOwnsSurfaceControlOpacity() {
+        return mWebViewOverlayProvider.mSurfaceControl != null;
+    }
+
+    /**
+     * Sets the SurfaceControl's opacity that this HardwareRenderer is rendering onto. The renderer
+     * may opt to override the opacity, and will return the value that is ultimately set
+     *
+     * @return true if the surface is opaque, false otherwise
+     *
+     * @hide
+     */
+    public boolean setSurfaceControlOpaque(boolean opaque) {
+        return mWebViewOverlayProvider.setSurfaceControlOpaque(opaque);
+    }
+
+    private void updateWebViewOverlayCallbacks() {
+        boolean shouldEnable = mWebViewOverlayProvider.shouldEnableOverlaySupport();
+        if (shouldEnable != mWebViewOverlaysEnabled) {
+            mWebViewOverlaysEnabled = shouldEnable;
+            if (shouldEnable) {
+                setASurfaceTransactionCallback(mWebViewOverlayProvider);
+                setPrepareSurfaceControlForWebviewCallback(mWebViewOverlayProvider);
+            } else {
+                setASurfaceTransactionCallback(null);
+                setPrepareSurfaceControlForWebviewCallback(null);
+            }
+        }
+    }
+
+    @Override
+    public void setSurfaceControl(@Nullable SurfaceControl surfaceControl) {
+        super.setSurfaceControl(surfaceControl);
+        mWebViewOverlayProvider.setSurfaceControl(surfaceControl);
+        updateWebViewOverlayCallbacks();
+    }
+
+    /**
+     * Sets the BLASTBufferQueue being used for rendering. This is required to be specified
+     * for WebView overlay support
+     */
+    public void setBlastBufferQueue(@Nullable BLASTBufferQueue blastBufferQueue) {
+        mWebViewOverlayProvider.setBLASTBufferQueue(blastBufferQueue);
+        updateWebViewOverlayCallbacks();
+    }
+
+    /**
      * Updates the light position based on the position of the window.
      *
      * @param attachInfo Information about the window.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f3ebe5b..cfb2130 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8204,7 +8204,10 @@
      * to populate information about the event source (this View), then calls
      * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to
      * populate the text content of the event source including its descendants,
-     * and last calls
+     * then for events type {@link AccessibilityEvent#TYPE_VIEW_SCROLLED}
+     * and {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} with
+     * subtype {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION},
+     * throttle the events, and last calls
      * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
      * on its parent to request sending of the event to interested parties.
      * <p>
@@ -8213,11 +8216,19 @@
      * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is
      * responsible for handling this call.
      * </p>
+     * <p>
+     * If this view uses {@link AccessibilityNodeProvider} to provide virtual view hierarchy rooted
+     * at this view, this method should not be called to send events from virtual children because
+     * it will populate the events with wrong information and the events should be throttled per
+     * child instead at the virtual root level. To send events from virtual children, call
+     * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} on the view's
+     * parent to request sending of the event to interested parties.
+     * </p>
      *
      * @param eventType The type of the event to send, as defined by several types from
-     * {@link android.view.accessibility.AccessibilityEvent}, such as
-     * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or
-     * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}.
+     * {@link AccessibilityEvent}, such as
+     * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} or
+     * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}.
      *
      * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
@@ -19816,6 +19827,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 +19847,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..9ed42f3 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -433,9 +433,8 @@
         mAmbiguousGestureMultiplier = Math.max(1.0f, multiplierValue.getFloat());
 
         // Size of the screen in bytes, in ARGB_8888 format
-        final WindowManager windowManager = context.getSystemService(WindowManager.class);
-        final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
-        mMaximumDrawingCacheSize = 4 * maxWindowBounds.width() * maxWindowBounds.height();
+        final Rect maxBounds = config.windowConfiguration.getMaxBounds();
+        mMaximumDrawingCacheSize = 4 * maxBounds.width() * maxBounds.height();
 
         mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
@@ -600,6 +599,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/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 488f7c3..d229cf6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2603,7 +2603,7 @@
      * It's the responsibility of the caller to recycle it once they're finished with it.
      * @param event The event to transform.
      * @param child The view whose coordinate space is to be used.
-     * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
+     * @return A copy of the given MotionEvent, transformed into the given View's coordinate
      *         space.
      */
     private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5bd3aef..9e2b6e0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -485,9 +485,6 @@
     protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
     private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
 
-    // Set to true if mSurfaceControl is used for Webview Overlay
-    private boolean mIsForWebviewOverlay;
-
     /**
      * Update the Choreographer's FrameInfo object with the timing information for the current
      * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
@@ -762,6 +759,12 @@
     private boolean mWaitForBlastSyncComplete = false;
 
     /**
+     * Keeps track of the last frame number that was attempted to draw. Should only be accessed on
+     * the RenderThread.
+     */
+    private long mRtLastAttemptedDrawFrameNum = 0;
+
+    /**
      * Keeps track of whether a traverse was triggered while the UI thread was paused. This can
      * occur when the client is waiting on another process to submit the transaction that
      * contains the buffer. The UI thread needs to wait on the callback before it can submit
@@ -1386,42 +1389,6 @@
         }
     }
 
-    /**
-     * Register a callback to be executed when Webview overlay needs to merge a transaction.
-     * This callback will be executed on RenderThread worker thread, and released inside native code
-     * when CanvasContext is destroyed.
-     */
-    private void addASurfaceTransactionCallback() {
-        HardwareRenderer.ASurfaceTransactionCallback callback = (nativeTransactionObj,
-                                                                 nativeSurfaceControlObj,
-                                                                 frameNr) -> {
-            if (mBlastBufferQueue == null) {
-                return false;
-            } else {
-                mBlastBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr);
-                return true;
-            }
-        };
-        mAttachInfo.mThreadedRenderer.setASurfaceTransactionCallback(callback);
-    }
-
-    /**
-     * Register a callback to be executed when Webview overlay needs a surface control.
-     * This callback will be executed on RenderThread worker thread, and released inside native code
-     * when CanvasContext is destroyed.
-     */
-    private void addPrepareSurfaceControlForWebviewCallback() {
-        HardwareRenderer.PrepareSurfaceControlForWebviewCallback callback = () -> {
-            // make mSurfaceControl transparent, so child surface controls are visible
-            if (mIsForWebviewOverlay) return;
-            synchronized (ViewRootImpl.this) {
-                mIsForWebviewOverlay = true;
-            }
-            mTransaction.setOpaque(mSurfaceControl, false).apply();
-        };
-        mAttachInfo.mThreadedRenderer.setPrepareSurfaceControlForWebviewCallback(callback);
-    }
-
     @UnsupportedAppUsage
     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
@@ -1466,11 +1433,8 @@
                     if (mHardwareRendererObserver != null) {
                         mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
                     }
-                    if (HardwareRenderer.isWebViewOverlaysEnabled()) {
-                        addPrepareSurfaceControlForWebviewCallback();
-                        addASurfaceTransactionCallback();
-                    }
                     mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
+                    mAttachInfo.mThreadedRenderer.setBlastBufferQueue(mBlastBufferQueue);
                 }
             }
         }
@@ -2041,6 +2005,7 @@
 
         if (mAttachInfo.mThreadedRenderer != null) {
             mAttachInfo.mThreadedRenderer.setSurfaceControl(null);
+            mAttachInfo.mThreadedRenderer.setBlastBufferQueue(null);
         }
     }
 
@@ -2469,7 +2434,7 @@
             mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
             mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
             mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
-                    mWindowAttributes.softInputMode));
+                    mWindowAttributes.softInputMode).toRect());
         }
         return mLastWindowInsets;
     }
@@ -4015,35 +3980,19 @@
     }
 
     /**
-     * The callback will run on the render thread.
+     * Only call this on the UI Thread.
      */
-    private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler,
-            boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) {
-        return frameNr -> {
-            if (DEBUG_BLAST) {
-                Log.d(mTag, "Received frameCompleteCallback frameNum=" + frameNr);
-            }
-
-            handler.postAtFrontOfQueue(() -> {
-                if (mNextDrawUseBlastSync) {
-                    // We don't need to synchronize mRtBLASTSyncTransaction here since we're
-                    // guaranteed that this is called after onFrameDraw and mNextDrawUseBlastSync
-                    // is only true when the UI thread is paused. Therefore, no one should be
-                    // modifying this object until the next vsync.
-                    mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
-                }
-
-                if (reportNextDraw) {
-                    // TODO: Use the frame number
-                    pendingDrawFinished();
-                }
-                if (commitCallbacks != null) {
-                    for (int i = 0; i < commitCallbacks.size(); i++) {
-                        commitCallbacks.get(i).run();
-                    }
-                }
-            });
-        };
+    void clearBlastSync() {
+        mNextDrawUseBlastSync = false;
+        mWaitForBlastSyncComplete = false;
+        if (DEBUG_BLAST) {
+            Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
+                    + " due to a previous skipped traversal.");
+        }
+        if (mRequestedTraverseWhilePaused) {
+            mRequestedTraverseWhilePaused = false;
+            scheduleTraversals();
+        }
     }
 
     /**
@@ -4053,30 +4002,86 @@
         return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
     }
 
-    private boolean addFrameCompleteCallbackIfNeeded() {
+    private boolean addFrameCompleteCallbackIfNeeded(boolean reportNextDraw) {
         if (!isHardwareEnabled()) {
             return false;
         }
 
+        if (!mNextDrawUseBlastSync && !reportNextDraw) {
+            return false;
+        }
+
+        if (DEBUG_BLAST) {
+            Log.d(mTag, "Creating frameCompleteCallback");
+        }
+
+        mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> {
+            long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum();
+            if (DEBUG_BLAST) {
+                Log.d(mTag, "Received frameCompleteCallback "
+                        + " lastAcquiredFrameNum=" + frameNr
+                        + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum);
+            }
+
+            boolean frameWasNotDrawn = frameNr != mRtLastAttemptedDrawFrameNum;
+            // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
+            // draw attempt. The next transaction and transaction complete callback were only set
+            // for the current draw attempt.
+            if (frameWasNotDrawn) {
+                mBlastBufferQueue.setNextTransaction(null);
+                mBlastBufferQueue.setTransactionCompleteCallback(mRtLastAttemptedDrawFrameNum,
+                        null);
+            }
+
+            mHandler.postAtFrontOfQueue(() -> {
+                if (mNextDrawUseBlastSync) {
+                    // We don't need to synchronize mRtBLASTSyncTransaction here since we're
+                    // guaranteed that this is called after onFrameDraw and mNextDrawUseBlastSync
+                    // is only true when the UI thread is paused. Therefore, no one should be
+                    // modifying this object until the next vsync.
+                    mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
+                }
+
+                if (reportNextDraw) {
+                    pendingDrawFinished();
+                }
+
+                if (frameWasNotDrawn) {
+                    clearBlastSync();
+                }
+            });
+        });
+        return true;
+    }
+
+    private void addFrameCommitCallbackIfNeeded() {
+        if (!isHardwareEnabled()) {
+            return;
+        }
+
         ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
                 .captureFrameCommitCallbacks();
-        final boolean needFrameCompleteCallback =
-                mNextDrawUseBlastSync || mReportNextDraw
-                        || (commitCallbacks != null && commitCallbacks.size() > 0);
-        if (needFrameCompleteCallback) {
-            if (DEBUG_BLAST) {
-                Log.d(mTag, "Creating frameCompleteCallback"
-                        + " mNextDrawUseBlastSync=" + mNextDrawUseBlastSync
-                        + " mReportNextDraw=" + mReportNextDraw
-                        + " commitCallbacks size="
-                        + (commitCallbacks == null ? 0 : commitCallbacks.size()));
-            }
-            mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(
-                    createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw,
-                            commitCallbacks));
-            return true;
+        final boolean needFrameCommitCallback =
+                (commitCallbacks != null && commitCallbacks.size() > 0);
+        if (!needFrameCommitCallback) {
+            return;
         }
-        return false;
+
+        if (DEBUG_DRAW) {
+            Log.d(mTag, "Creating frameCommitCallback"
+                    + " commitCallbacks size=" + commitCallbacks.size());
+        }
+        mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> {
+            if (DEBUG_DRAW) {
+                Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer);
+            }
+
+            mHandler.postAtFrontOfQueue(() -> {
+                for (int i = 0; i < commitCallbacks.size(); i++) {
+                    commitCallbacks.get(i).run();
+                }
+            });
+        });
     }
 
     private void addFrameCallbackIfNeeded() {
@@ -4106,6 +4111,8 @@
                         + " Creating transactionCompleteCallback=" + nextDrawUseBlastSync);
             }
 
+            mRtLastAttemptedDrawFrameNum = frame;
+
             if (needsCallbackForBlur) {
                 mBlurRegionAggregator
                     .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates);
@@ -4128,18 +4135,7 @@
                     if (DEBUG_BLAST) {
                         Log.d(mTag, "Received transactionCompleteCallback frameNum=" + frame);
                     }
-                    mHandler.postAtFrontOfQueue(() -> {
-                        mNextDrawUseBlastSync = false;
-                        mWaitForBlastSyncComplete = false;
-                        if (DEBUG_BLAST) {
-                            Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
-                                    + " due to a previous skipped traversal.");
-                        }
-                        if (mRequestedTraverseWhilePaused) {
-                            mRequestedTraverseWhilePaused = false;
-                            scheduleTraversals();
-                        }
-                    });
+                    mHandler.postAtFrontOfQueue(this::clearBlastSync);
                 });
             } else if (reportNextDraw) {
                 // If we need to report next draw, wait for adapter to flush its shadow queue
@@ -4165,8 +4161,9 @@
         mIsDrawing = true;
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
 
-        boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded();
         addFrameCallbackIfNeeded();
+        addFrameCommitCallbackIfNeeded();
+        boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(mReportNextDraw);
 
         try {
             boolean canUseAsync = draw(fullRedrawNeeded);
@@ -7823,11 +7820,8 @@
                 }
             }
             if (mAttachInfo.mThreadedRenderer != null) {
-                if (HardwareRenderer.isWebViewOverlaysEnabled()) {
-                    addPrepareSurfaceControlForWebviewCallback();
-                    addASurfaceTransactionCallback();
-                }
                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
+                mAttachInfo.mThreadedRenderer.setBlastBufferQueue(mBlastBufferQueue);
             }
         } else {
             destroySurface();
@@ -7873,11 +7867,10 @@
             return;
         }
 
-        synchronized (this) {
-            if (mIsForWebviewOverlay) {
-                mIsSurfaceOpaque = false;
-                return;
-            }
+        final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
+        if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) {
+            opaque = renderer.setSurfaceControlOpaque(opaque);
+        } else {
             mTransaction.setOpaque(mSurfaceControl, opaque).apply();
         }
 
@@ -9522,6 +9515,7 @@
 
         ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
         response.setWindowTitle(getTitle().toString());
+        response.setPackageName(mContext.getPackageName());
 
         StringWriter writer =  new StringWriter();
         IndentingPrintWriter pw = new IndentingPrintWriter(writer);
@@ -9936,7 +9930,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 eb410ab..9a57e74 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -320,6 +320,25 @@
     int TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE = 27;
 
     /**
+     * A window in a new task fragment is being opened.
+     * @hide
+     */
+    int TRANSIT_OLD_TASK_FRAGMENT_OPEN = 28;
+
+    /**
+     * A window in the top-most activity of task fragment is being closed to reveal the activity
+     * below.
+     * @hide
+     */
+    int TRANSIT_OLD_TASK_FRAGMENT_CLOSE = 29;
+
+    /**
+     * A window of task fragment is changing bounds.
+     * @hide
+     */
+    int TRANSIT_OLD_TASK_FRAGMENT_CHANGE = 30;
+
+    /**
      * @hide
      */
     @IntDef(prefix = { "TRANSIT_OLD_" }, value = {
@@ -344,7 +363,10 @@
             TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN,
             TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE,
             TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE,
-            TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE
+            TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
+            TRANSIT_OLD_TASK_FRAGMENT_OPEN,
+            TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
+            TRANSIT_OLD_TASK_FRAGMENT_CHANGE
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionOldType {}
@@ -381,8 +403,11 @@
     int TRANSIT_CHANGE = 6;
     /**
      * The keyguard was visible and has been dismissed.
+     * @deprecated use {@link #TRANSIT_TO_BACK} + {@link #TRANSIT_FLAG_KEYGUARD_GOING_AWAY} for
+     *             keyguard going away with Shell transition.
      * @hide
      */
+    @Deprecated
     int TRANSIT_KEYGUARD_GOING_AWAY = 7;
     /**
      * A window is appearing above a locked keyguard.
@@ -487,6 +512,12 @@
     int TRANSIT_FLAG_IS_RECENTS = 0x80;
 
     /**
+     * Transition flag: Indicates that keyguard should go away with this transition.
+     * @hide
+     */
+    int TRANSIT_FLAG_KEYGUARD_GOING_AWAY = 0x100;
+
+    /**
      * @hide
      */
     @IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -497,7 +528,8 @@
             TRANSIT_FLAG_APP_CRASHED,
             TRANSIT_FLAG_OPEN_BEHIND,
             TRANSIT_FLAG_KEYGUARD_LOCKED,
-            TRANSIT_FLAG_IS_RECENTS
+            TRANSIT_FLAG_IS_RECENTS,
+            TRANSIT_FLAG_KEYGUARD_GOING_AWAY
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionFlags {}
@@ -2095,6 +2127,7 @@
          * {@hide}
          */
         @UnsupportedAppUsage
+        @TestApi
         public static final int FLAG_SLIPPERY = 0x20000000;
 
         /**
@@ -3499,6 +3532,14 @@
         public Insets providedInternalInsets = Insets.NONE;
 
         /**
+         * If specified, the insets provided by this window for the IME will be our window frame
+         * minus the insets specified by providedInternalImeInsets.
+         *
+         * @hide
+         */
+        public Insets providedInternalImeInsets = Insets.NONE;
+
+        /**
          * {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
          * This will make layout during rotation change smoothly.
          *
@@ -3872,6 +3913,7 @@
                 out.writeInt(0);
             }
             providedInternalInsets.writeToParcel(out, 0 /* parcelableFlags */);
+            providedInternalImeInsets.writeToParcel(out, 0 /* parcelableFlags */);
             if (paramsForRotation != null) {
                 checkNonRecursiveParams();
                 out.writeInt(paramsForRotation.length);
@@ -3951,6 +3993,7 @@
                 in.readIntArray(providesInsetsTypes);
             }
             providedInternalInsets = Insets.CREATOR.createFromParcel(in);
+            providedInternalImeInsets = Insets.CREATOR.createFromParcel(in);
             int paramsForRotationLength = in.readInt();
             if (paramsForRotationLength > 0) {
                 paramsForRotation = new LayoutParams[paramsForRotationLength];
@@ -4257,6 +4300,11 @@
                 changes |= LAYOUT_CHANGED;
             }
 
+            if (!providedInternalImeInsets.equals(o.providedInternalImeInsets)) {
+                providedInternalImeInsets = o.providedInternalImeInsets;
+                changes |= LAYOUT_CHANGED;
+            }
+
             if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) {
                 paramsForRotation = o.paramsForRotation;
                 checkNonRecursiveParams();
@@ -4462,6 +4510,10 @@
                 sb.append(" providedInternalInsets=");
                 sb.append(providedInternalInsets);
             }
+            if (!providedInternalImeInsets.equals(Insets.NONE)) {
+                sb.append(" providedInternalImeInsets=");
+                sb.append(providedInternalImeInsets);
+            }
             if (paramsForRotation != null && paramsForRotation.length != 0) {
                 sb.append(System.lineSeparator());
                 sb.append(prefix).append("  paramsForRotation=");
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f8009919..7bd156b 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,12 +16,16 @@
 
 package android.view;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+import static android.window.WindowProviderService.isWindowProviderService;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
@@ -36,7 +40,9 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.window.WindowContext;
+import android.window.WindowProvider;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IResultReceiver;
@@ -145,6 +151,7 @@
             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
         }
         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
+        assertWindowContextTypeMatches(wparams.type);
         // Only use the default token if we don't have a parent window and a token.
         if (mDefaultToken != null && mParentWindow == null && wparams.token == null) {
             wparams.token = mDefaultToken;
@@ -152,6 +159,34 @@
         wparams.mWindowContextToken = mWindowContextToken;
     }
 
+    private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) {
+        if (!(mContext instanceof WindowProvider)) {
+            return;
+        }
+        // Don't need to check sub-window type because sub window should be allowed to be attached
+        // to the parent window.
+        if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) {
+            return;
+        }
+        final WindowProvider windowProvider = (WindowProvider) mContext;
+        if (windowProvider.getWindowType() == windowType) {
+            return;
+        }
+        IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch."
+                + " Window Context's window type is " + windowProvider.getWindowType()
+                + ", while LayoutParams' type is set to " + windowType + "."
+                + " Please create another Window Context via"
+                + " createWindowContext(getDisplay(), " + windowType + ", null)"
+                + " to add window with type:" + windowType);
+        if (!isWindowProviderService(windowProvider.getWindowContextOptions())) {
+            throw exception;
+        }
+        // Throw IncorrectCorrectViolation if the Window Context is allowed to provide multiple
+        // window types. Usually it's because the Window Context is a WindowProviderService.
+        StrictMode.onIncorrectContextUsed("WindowContext's window type must"
+                + " match type in WindowManager.LayoutParams", exception);
+    }
+
     @Override
     public void removeView(View view) {
         mGlobal.removeView(view, false);
@@ -266,7 +301,6 @@
         }
     }
 
-    // TODO(b/150095967): Set window type to LayoutParams
     private WindowInsets computeWindowInsets(Rect bounds) {
         // Initialize params which used for obtaining all system insets.
         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
@@ -288,10 +322,10 @@
                     .getWindowInsets(attrs, mContext.getDisplayId(), insetsState);
             final Configuration config = mContext.getResources().getConfiguration();
             final boolean isScreenRound = config.isScreenRound();
-            final int windowingMode = config.windowConfiguration.getWindowingMode();
             return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
                     isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
-                    SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode, null /* typeSideMap */);
+                    SYSTEM_UI_FLAG_VISIBLE, attrs.type, WINDOWING_MODE_FULLSCREEN,
+                    null /* typeSideMap */);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index bbef3e6..e634d60 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -209,4 +209,41 @@
                 return Integer.toString(why);
         }
     }
+
+    /**
+     * How much to multiply the policy's type layer, to reserve room
+     * for multiple windows of the same type and Z-ordering adjustment
+     * with TYPE_LAYER_OFFSET.
+     */
+    int TYPE_LAYER_MULTIPLIER = 10000;
+
+    /**
+     * Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
+     * or below others in the same layer.
+     */
+    int TYPE_LAYER_OFFSET = 1000;
+
+    /**
+     * How much to increment the layer for each window, to reserve room
+     * for effect surfaces between them.
+     */
+    int WINDOW_LAYER_MULTIPLIER = 5;
+
+    /**
+     * Animation thumbnail is as far as possible below the window above
+     * the thumbnail (or in other words as far as possible above the window
+     * below it).
+     */
+    int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER - 1;
+
+    int SPLIT_DIVIDER_LAYER = TYPE_LAYER_MULTIPLIER * 3;
+    int WATERMARK_LAYER = TYPE_LAYER_MULTIPLIER * 100;
+    int STRICT_MODE_LAYER = TYPE_LAYER_MULTIPLIER * 101;
+    int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
+
+    /**
+     * Layers for screen rotation animation. We put these layers above
+     * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows.
+     */
+    int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
 }
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index d14dc6e..dc01990 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -16,6 +16,9 @@
 
 package android.view.accessibility;
 
+
+import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_ACCESSIBILITY;
+
 import android.os.Build;
 import android.util.ArraySet;
 import android.util.Log;
@@ -70,6 +73,7 @@
     private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
     private int mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+    private int mInputFocusWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
 
     private boolean mIsAllWindowsCached;
 
@@ -190,6 +194,7 @@
                         removeCachedNodeLocked(event.getWindowId(), mInputFocus);
                     }
                     mInputFocus = event.getSourceNodeId();
+                    mInputFocusWindow = event.getWindowId();
                     nodeToRefresh = removeCachedNodeLocked(event.getWindowId(), mInputFocus);
                 } break;
 
@@ -439,6 +444,7 @@
             }
             if (clone.isFocused()) {
                 mInputFocus = sourceId;
+                mInputFocusWindow = windowId;
             }
         }
     }
@@ -462,6 +468,7 @@
             mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
             mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+            mInputFocusWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
         }
     }
 
@@ -486,6 +493,87 @@
     }
 
     /**
+     * Gets a cached {@link AccessibilityNodeInfo} with focus according to focus type.
+     *
+     * Note: {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID} will return
+     * null.
+     *
+     * @param focusType The focus type.
+     * @param windowId A unique window id.
+     * @param initialNodeId A unique view id or virtual descendant id from where to start the
+     *                      search.
+     * @return The cached {@link AccessibilityNodeInfo} if it has a11y focus or null if such not
+     * found.
+     */
+    public AccessibilityNodeInfo getFocus(int focusType, long initialNodeId, int windowId) {
+        synchronized (mLock) {
+            int currentFocusWindowId;
+            long currentFocusId;
+            if (focusType == FOCUS_ACCESSIBILITY) {
+                currentFocusWindowId = mAccessibilityFocusedWindow;
+                currentFocusId = mAccessibilityFocus;
+            } else {
+                currentFocusWindowId = mInputFocusWindow;
+                currentFocusId = mInputFocus;
+            }
+
+            if (currentFocusWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+                return null;
+            }
+
+            if (windowId != AccessibilityWindowInfo.ANY_WINDOW_ID
+                    && windowId != currentFocusWindowId) {
+                return null;
+            }
+
+            LongSparseArray<AccessibilityNodeInfo> nodes =
+                    mNodeCache.get(currentFocusWindowId);
+            if (nodes == null) {
+                return null;
+            }
+
+            final AccessibilityNodeInfo currentFocusedNode = nodes.get(currentFocusId);
+            if (currentFocusedNode == null) {
+                return null;
+            }
+
+            if (initialNodeId == currentFocusId || (isCachedNodeOrDescendantLocked(
+                    currentFocusedNode.getParentNodeId(), initialNodeId, nodes))) {
+                if (VERBOSE) {
+                    Log.i(LOG_TAG, "getFocus(0x" + Long.toHexString(currentFocusId) + ") = "
+                            + currentFocusedNode + " with type: "
+                            + (focusType == FOCUS_ACCESSIBILITY
+                            ? "FOCUS_ACCESSIBILITY"
+                            : "FOCUS_INPUT"));
+                }
+                // Return a copy since the client calls to AccessibilityNodeInfo#recycle()
+                // will wipe the data of the cached info.
+                return new AccessibilityNodeInfo(currentFocusedNode);
+            }
+
+            if (VERBOSE) {
+                Log.i(LOG_TAG, "getFocus is null with type: "
+                        + (focusType == FOCUS_ACCESSIBILITY
+                        ? "FOCUS_ACCESSIBILITY"
+                        : "FOCUS_INPUT"));
+            }
+            return null;
+        }
+    }
+
+    private boolean isCachedNodeOrDescendantLocked(long nodeId, long ancestorId,
+            LongSparseArray<AccessibilityNodeInfo> nodes) {
+        if (ancestorId == nodeId) {
+            return true;
+        }
+        AccessibilityNodeInfo node = nodes.get(nodeId);
+        if (node == null) {
+            return false;
+        }
+        return isCachedNodeOrDescendantLocked(node.getParentNodeId(), ancestorId,  nodes);
+    }
+
+    /**
      * Clears nodes for the window with the given id
      */
     private void clearNodesForWindowLocked(int windowId) {
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 40da86a..ff6f8ac 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -613,6 +613,36 @@
     public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 0x00000040;
 
     /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * A drag has started while accessibility is enabled. This is either via an
+     * AccessibilityAction, or via touch events. This is sent from the source that initiated the
+     * drag.
+     *
+     * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START
+     */
+    public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 0x00000080;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * A drag in with accessibility enabled has ended. This means the content has been
+     * successfully dropped. This is sent from the target that accepted the dragged content.
+     *
+     * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_DROP
+     */
+    public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 0x00000100;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * A drag in with accessibility enabled has ended. This means the content has been
+     * unsuccessfully dropped, the user has canceled the action via an AccessibilityAction, or
+     * no drop has been detected within a timeout and the drag was automatically cancelled. This is
+     * sent from the source that initiated the drag.
+     *
+     * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_CANCEL
+     */
+    public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200;
+
+    /**
      * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
      * The window was added.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 80ef6cf..6975bb2 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -22,6 +22,7 @@
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -114,8 +115,7 @@
         from a window, mapping from windowId -> timestamp. */
     private static final SparseLongArray sScrollingWindows = new SparseLongArray();
 
-    private static AccessibilityCache sAccessibilityCache =
-            new AccessibilityCache(new AccessibilityCache.AccessibilityNodeRefresher());
+    private static AccessibilityCache sAccessibilityCache;
 
     private final AtomicInteger mInteractionIdCounter = new AtomicInteger();
 
@@ -150,7 +150,7 @@
     @UnsupportedAppUsage()
     public static AccessibilityInteractionClient getInstance() {
         final long threadId = Thread.currentThread().getId();
-        return getInstanceForThread(threadId);
+        return getInstanceForThread(threadId, true);
     }
 
     /**
@@ -161,11 +161,17 @@
      *
      * @return The client for a given <code>threadId</code>.
      */
-    public static AccessibilityInteractionClient getInstanceForThread(long threadId) {
+    public static AccessibilityInteractionClient getInstanceForThread(long threadId,
+            boolean initializeCache) {
         synchronized (sStaticLock) {
             AccessibilityInteractionClient client = sClients.get(threadId);
             if (client == null) {
-                client = new AccessibilityInteractionClient();
+                if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+                    // Don't initialize a cache for the system process
+                    client = new AccessibilityInteractionClient(false);
+                } else {
+                    client = new AccessibilityInteractionClient(initializeCache);
+                }
                 sClients.put(threadId, client);
             }
             return client;
@@ -176,11 +182,20 @@
      * @return The client for the current thread.
      */
     public static AccessibilityInteractionClient getInstance(Context context) {
+        return getInstance(/* initializeCache= */true, context);
+    }
+
+    /**
+     * @param initializeCache whether to initialize the cache in a new client instance
+     * @return The client for the current thread.
+     */
+    public static AccessibilityInteractionClient getInstance(boolean initializeCache,
+            Context context) {
         final long threadId = Thread.currentThread().getId();
         if (context != null) {
-            return getInstanceForThread(threadId, context);
+            return getInstanceForThread(threadId, initializeCache, context);
         }
-        return getInstanceForThread(threadId);
+        return getInstanceForThread(threadId, initializeCache);
     }
 
     /**
@@ -189,14 +204,19 @@
      * We do not have a thread local variable since other threads should be able to
      * look up the correct client knowing a thread id. See ViewRootImpl for details.
      *
+     * @param initializeCache whether to initialize the cache in a new client instance
      * @return The client for a given <code>threadId</code>.
      */
     public static AccessibilityInteractionClient getInstanceForThread(
-            long threadId, Context context) {
+            long threadId, boolean initializeCache, Context context) {
         synchronized (sStaticLock) {
             AccessibilityInteractionClient client = sClients.get(threadId);
             if (client == null) {
-                client = new AccessibilityInteractionClient(context);
+                if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+                    client = new AccessibilityInteractionClient(false, context);
+                } else {
+                    client = new AccessibilityInteractionClient(initializeCache, context);
+                }
                 sClients.put(threadId, client);
             }
             return client;
@@ -249,13 +269,26 @@
 
     private AccessibilityInteractionClient() {
         /* reducing constructor visibility */
+        this(true);
+    }
+
+    private AccessibilityInteractionClient(boolean initializeCache) {
+        initializeCache(initializeCache);
         mAccessibilityManager = null;
     }
 
-    private AccessibilityInteractionClient(Context context) {
+    private AccessibilityInteractionClient(boolean initializeCache, Context context) {
+        initializeCache(initializeCache);
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
     }
 
+    private static void initializeCache(boolean initialize) {
+        if (initialize && sAccessibilityCache == null) {
+            sAccessibilityCache = new AccessibilityCache(
+                    new AccessibilityCache.AccessibilityNodeRefresher());
+        }
+    }
+
     /**
      * Sets the message to be processed if the interacted view hierarchy
      * and the interacting client are running in the same thread.
@@ -311,7 +344,7 @@
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 AccessibilityWindowInfo window;
-                if (!bypassCache) {
+                if (!bypassCache && sAccessibilityCache != null) {
                     window = sAccessibilityCache.getWindow(accessibilityWindowId);
                     if (window != null) {
                         if (DEBUG) {
@@ -341,7 +374,7 @@
                             + bypassCache);
                 }
 
-                if (window != null) {
+                if (window != null && sAccessibilityCache != null) {
                     if (!bypassCache) {
                         sAccessibilityCache.addWindow(window);
                     }
@@ -384,21 +417,24 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                SparseArray<List<AccessibilityWindowInfo>> windows =
-                        sAccessibilityCache.getWindowsOnAllDisplays();
-                if (windows != null) {
+                SparseArray<List<AccessibilityWindowInfo>> windows;
+                if (sAccessibilityCache != null) {
+                    windows = sAccessibilityCache.getWindowsOnAllDisplays();
+                    if (windows != null) {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Windows cache hit");
+                        }
+                        if (shouldTraceClient()) {
+                            logTraceClient(
+                                    connection, "getWindows cache", "connectionId=" + connectionId);
+                        }
+                        return windows;
+                    }
                     if (DEBUG) {
-                        Log.i(LOG_TAG, "Windows cache hit");
+                        Log.i(LOG_TAG, "Windows cache miss");
                     }
-                    if (shouldTraceClient()) {
-                        logTraceClient(
-                                connection, "getWindows cache", "connectionId=" + connectionId);
-                    }
-                    return windows;
                 }
-                if (DEBUG) {
-                    Log.i(LOG_TAG, "Windows cache miss");
-                }
+
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
                     windows = connection.getWindows();
@@ -409,7 +445,9 @@
                     logTraceClient(connection, "getWindows", "connectionId=" + connectionId);
                 }
                 if (windows != null) {
-                    sAccessibilityCache.setWindowsOnAllDisplays(windows);
+                    if (sAccessibilityCache != null) {
+                        sAccessibilityCache.setWindowsOnAllDisplays(windows);
+                    }
                     return windows;
                 }
             } else {
@@ -493,7 +531,7 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                if (!bypassCache) {
+                if (!bypassCache && sAccessibilityCache != null) {
                     AccessibilityNodeInfo cachedInfo = sAccessibilityCache.getNode(
                             accessibilityWindowId, accessibilityNodeId);
                     if (cachedInfo != null) {
@@ -725,7 +763,9 @@
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
      *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
-     *     to query the currently active window.
+     *     to query the currently active window. Use
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ANY_WINDOW_ID} to query all
+     *     windows
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
      *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
@@ -733,11 +773,28 @@
      * @param focusType The focus type.
      * @return The accessibility focused {@link AccessibilityNodeInfo}.
      */
+    @SuppressLint("LongLogTag")
     public AccessibilityNodeInfo findFocus(int connectionId, int accessibilityWindowId,
             long accessibilityNodeId, int focusType) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
+                if (sAccessibilityCache != null) {
+                    AccessibilityNodeInfo cachedInfo = sAccessibilityCache.getFocus(focusType,
+                            accessibilityNodeId, accessibilityWindowId);
+                    if (cachedInfo != null) {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Focused node cache hit retrieved"
+                                    + idToString(cachedInfo.getWindowId(),
+                                    cachedInfo.getSourceNodeId()));
+                        }
+                        return cachedInfo;
+                    }
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Focused node cache miss with "
+                                + idToString(accessibilityWindowId, accessibilityNodeId));
+                    }
+                }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 if (shouldTraceClient()) {
                     logTraceClient(connection, "findFocus",
@@ -901,7 +958,9 @@
      */
     @UnsupportedAppUsage()
     public void clearCache() {
-        sAccessibilityCache.clear();
+        if (sAccessibilityCache != null) {
+            sAccessibilityCache.clear();
+        }
     }
 
     public void onAccessibilityEvent(AccessibilityEvent event) {
@@ -917,7 +976,9 @@
             default:
                 break;
         }
-        sAccessibilityCache.onAccessibilityEvent(event);
+        if (sAccessibilityCache != null) {
+            sAccessibilityCache.onAccessibilityEvent(event);
+        }
     }
 
     /**
@@ -1153,7 +1214,7 @@
                 }
             }
             info.setSealed(true);
-            if (!bypassCache) {
+            if (!bypassCache && sAccessibilityCache != null) {
                 sAccessibilityCache.add(info);
             }
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 085eb81..587a270 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -27,6 +27,7 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ClipData;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Build;
@@ -4353,6 +4354,14 @@
             case R.id.accessibilityActionImeEnter:
                 return "ACTION_IME_ENTER";
             default:
+                // TODO(197520937): Use finalized constants in switch
+                if (action == R.id.accessibilityActionDragStart) {
+                    return "ACTION_DRAG";
+                } else if (action == R.id.accessibilityActionDragCancel) {
+                    return "ACTION_CANCEL_DRAG";
+                } else if (action == R.id.accessibilityActionDragDrop) {
+                    return "ACTION_DROP";
+                }
                 return "ACTION_UNKNOWN";
         }
     }
@@ -4995,6 +5004,46 @@
         @NonNull public static final AccessibilityAction ACTION_IME_ENTER =
                 new AccessibilityAction(R.id.accessibilityActionImeEnter);
 
+        /**
+         * Action to start a drag.
+         * <p>
+         * This action initiates a drag & drop within the system. The source's dragged content is
+         * prepared before the drag begins. In View, this action should prepare the arguments to
+         * {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} and then
+         * call {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}. The
+         * equivalent should be performed for other UI toolkits.
+         * </p>
+         *
+         * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED
+         */
+        @NonNull public static final AccessibilityAction ACTION_DRAG_START =
+                new AccessibilityAction(R.id.accessibilityActionDragStart);
+
+        /**
+         * Action to trigger a drop of the content being dragged.
+         * <p>
+         * This action is added to potential drop targets if the source started a drag with
+         * {@link #ACTION_DRAG_START}. In View, these targets are Views that accepted
+         * {@link android.view.DragEvent#ACTION_DRAG_STARTED} and have an
+         * {@link View.OnDragListener}.
+         * </p>
+         *
+         * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED
+         */
+        @NonNull public static final AccessibilityAction ACTION_DRAG_DROP =
+                new AccessibilityAction(R.id.accessibilityActionDragDrop);
+
+        /**
+         * Action to cancel a drag.
+         * <p>
+         * This action is added to the source that started a drag with {@link #ACTION_DRAG_START}.
+         * </p>
+         *
+         * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED
+         */
+        @NonNull public static final AccessibilityAction ACTION_DRAG_CANCEL =
+                new AccessibilityAction(R.id.accessibilityActionDragCancel);
+
         private final int mActionId;
         private final CharSequence mLabel;
 
diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java
index d4cd968..c47f6f7 100644
--- a/core/java/android/view/autofill/AutofillClientController.java
+++ b/core/java/android/view/autofill/AutofillClientController.java
@@ -324,7 +324,7 @@
 
     @Override
     public boolean autofillClientIsVisibleForAutofill() {
-        return !mActivity.isStopped();
+        return mActivity.isVisibleForAutofill();
     }
 
     @Override
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 c023c6e..139b69c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -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;
                 }
@@ -1381,8 +1381,7 @@
     public boolean isAcceptingText() {
         checkFocus();
         synchronized (mH) {
-            return mServedInputConnection != null
-                    && mServedInputConnection.getInputConnection() != null;
+            return mServedInputConnection != null && !mServedInputConnection.isFinished();
         }
     }
 
@@ -2135,6 +2134,7 @@
      * @hide
      */
     public boolean requestImeShow(IBinder windowToken) {
+        checkFocus();
         synchronized (mH) {
             final View servedView = getServedViewLocked();
             if (servedView == null || servedView.getWindowToken() != windowToken) {
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
index 54c455c..6610375 100644
--- a/core/java/android/view/translation/TranslationManager.java
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -23,12 +23,12 @@
 import android.annotation.WorkerThread;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.ParceledListSlice;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.Looper;
-import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SynchronousResultReceiver;
 import android.util.ArrayMap;
@@ -271,13 +271,10 @@
             if (result.resultCode != STATUS_SYNC_CALL_SUCCESS) {
                 return Collections.emptySet();
             }
-            Parcelable[] parcelables = result.bundle.getParcelableArray(EXTRA_CAPABILITIES);
-            ArraySet<TranslationCapability> capabilities = new ArraySet();
-            for (Parcelable obj : parcelables) {
-                if (obj instanceof TranslationCapability) {
-                    capabilities.add((TranslationCapability) obj);
-                }
-            }
+            ParceledListSlice<TranslationCapability> listSlice =
+                    result.bundle.getParcelable(EXTRA_CAPABILITIES);
+            ArraySet<TranslationCapability> capabilities =
+                    new ArraySet<>(listSlice == null ? null : listSlice.getList());
             return capabilities;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
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/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index a833591..442d099 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -356,7 +356,11 @@
             }
             for (int i = 0; i < translatedResult.size(); i++) {
                 final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i));
-                final View view = mViews.get(autofillId).get();
+                final WeakReference<View> viewRef = mViews.get(autofillId);
+                if (viewRef == null) {
+                    continue;
+                }
+                final View view = viewRef.get();
                 if (view == null) {
                     Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
                             + " may be gone.");
@@ -416,7 +420,11 @@
                     Log.w(TAG, "No AutofillId is set in ViewTranslationResponse");
                     continue;
                 }
-                final View view = mViews.get(autofillId).get();
+                final WeakReference<View> viewRef = mViews.get(autofillId);
+                if (viewRef == null) {
+                    continue;
+                }
+                final View view = viewRef.get();
                 if (view == null) {
                     Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
                             + " may be gone.");
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index b9ed32c..3012e93 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 import android.view.View;
 import android.view.autofill.AutofillId;
+import android.widget.TextView;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -42,11 +43,50 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
-// TODO(b/178044703): Describe what UI Translation is.
 /**
- * The {@link UiTranslationManager} class provides ways for apps to use the ui translation
+ * <p>The {@link UiTranslationManager} class provides ways for apps to use the ui translation
  * function in framework.
+ *
+ * <p> The UI translation provides ways for apps to support inline translation for the views. For
+ * example the system supports text translation for {@link TextView}. To support UI translation for
+ * your views, you should override the following methods to provide the content to be translated
+ * and deal with the translated result. Here is an example for {@link TextView}-like views:
+ *
+ * <pre><code>
+ * public class MyTextView extends View {
+ *     public MyTextView(...) {
+ *         // implements how to show the translated result in your View in
+ *         // ViewTranslationCallback and set it by setViewTranslationCallback()
+ *         setViewTranslationCallback(new MyViewTranslationCallback());
+ *     }
+ *
+ *     public void onCreateViewTranslationRequest(int[] supportedFormats,
+ *             Consumer<ViewTranslationRequest> requestsCollector) {
+ *        // collect the information that needs to be translated
+ *        ViewTranslationRequest.Builder requestBuilder =
+ *                     new ViewTranslationRequest.Builder(getAutofillId());
+ *        requestBuilder.setValue(ViewTranslationRequest.ID_TEXT,
+ *                         TranslationRequestValue.forText(etText()));
+ *        requestsCollector.accept(requestBuilder.build());
+ *     }
+ *
+ *     public void onProvideContentCaptureStructure(
+ *             ViewStructure structure, int flags) {
+ *         // set ViewTranslationResponse
+ *         super.onViewTranslationResponse(response);
+ *     }
+ * }
+ * </code></pre>
+ *
+ * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws the
+ * HTML using {@link android.graphics.Canvas} or native libraries in a different render process),
+ * you must override {@link View#onCreateVirtualViewTranslationRequests(long[], int[], Consumer)} to
+ * provide the content to be translated and implement
+ * {@link View#onVirtualViewTranslationResponses(android.util.LongSparseArray)} for the translated
+ * result. You also need to implement {@link android.view.translation.ViewTranslationCallback} to
+ * handle the translated information show or hide in your {@link View}.
  */
 public final class UiTranslationManager {
 
@@ -248,14 +288,14 @@
         }
     }
 
-    // TODO(b/178044703): Fix the View API link when it becomes public.
     /**
      * Register for notifications of UI Translation state changes on the foreground activity. This
      * is available to the owning application itself and also the current input method.
      * <p>
      * The application whose UI is being translated can use this to customize the UI Translation
      * behavior in ways that aren't made easy by methods like
-     * View#onCreateTranslationRequest().
+     * {@link View#onCreateViewTranslationRequest(int[], Consumer)}.
+     *
      * <p>
      * Input methods can use this to offer complementary features to UI Translation; for example,
      * enabling outgoing message translation when the system is translating incoming messages in a
diff --git a/core/java/android/view/translation/ViewTranslationCallback.java b/core/java/android/view/translation/ViewTranslationCallback.java
index 6efd621..a075662 100644
--- a/core/java/android/view/translation/ViewTranslationCallback.java
+++ b/core/java/android/view/translation/ViewTranslationCallback.java
@@ -19,9 +19,17 @@
 import android.annotation.NonNull;
 import android.annotation.UiThread;
 import android.view.View;
+import android.view.contentcapture.ContentCaptureSession;
 
 /**
- * Callback for handling the translated information show or hide in the {@link View}.
+ * <p> Callback for handling the translated information show or hide in the {@link View}.
+ *
+ * <p> When the platform intelligence starts translation of an app's ui, the system will call
+ * {@link View#dispatchCreateViewTranslationRequest} to collect the {@link ViewTranslationRequest}s
+ * for translation purpose by traversing the hierarchy then send to translation service. After
+ * receiving the {@link ViewTranslationResponse}, the system will call
+ * {@link ViewTranslationCallback#onShowTranslation(View)} to show the translated information for
+ * the {@link View}.
  */
 @UiThread
 public interface ViewTranslationCallback {
@@ -33,13 +41,19 @@
      * method will not be called before {@link View#onViewTranslationResponse} or
      * {@link View#onVirtualViewTranslationResponses}.
      *
+     * <p> NOTE: For TextView implementation, {@link ContentCaptureSession#notifyViewTextChanged}
+     * shouldn't be called with the translated text, simply calling setText() here will trigger the
+     * method. You should either override {@code View#onProvideContentCaptureStructure()} to report
+     * the original text instead of the translated text or use a different approach to display the
+     * translated text.
+     *
      * See {@link View#onViewTranslationResponse} for how to get the translated information.
      *
      * @return {@code true} if the View handles showing the translation.
      */
     boolean onShowTranslation(@NonNull View view);
     /**
-     * Called when the user wants to show the original text instead of the translated text. This
+     * Called when user wants to view the original content instead of the translated content. This
      * method will not be called before {@link View#onViewTranslationResponse} or
      * {@link View#onViewTranslationResponse}.
      *
@@ -47,7 +61,8 @@
      */
     boolean onHideTranslation(@NonNull View view);
     /**
-     * Called when the user finish the Ui translation and no longer to show the translated text.
+     * Called when the translation state is no longer needed. It should restore the original content
+     * and clear all saved states.
      *
      * @return {@code true} if the View handles clearing the translation.
      */
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 91fc5a5..fe5eb08 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -740,6 +740,16 @@
         }
 
         @Override
+        public UserHandle getUser() {
+            return mContextForResources.getUser();
+        }
+
+        @Override
+        public int getUserId() {
+            return mContextForResources.getUserId();
+        }
+
+        @Override
         public boolean isRestricted() {
             // Override isRestricted and direct to resource's implementation. The isRestricted is
             // used for determining the risky resources loading, e.g. fonts, thus direct to context
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5500ff0..69a5e39 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11872,6 +11872,15 @@
 
                 if (text != null) {
                     if (expandedTopChar > 0 || expandedBottomChar < text.length()) {
+                        // Cap the offsets to avoid an OOB exception. That can happen if the
+                        // displayed/layout text, on which these offsets are calculated, is longer
+                        // than the original text (such as when the view is translated by the
+                        // platform intelligence).
+                        // TODO(b/196433694): Figure out how to better handle the offset
+                        // calculations for this case (so we don't unnecessarily cutoff the original
+                        // text, for example).
+                        expandedTopChar = Math.min(expandedTopChar, text.length());
+                        expandedBottomChar = Math.min(expandedBottomChar, text.length());
                         text = text.subSequence(expandedTopChar, expandedBottomChar);
                     }
 
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index 0ca8a86..1ad0452 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -16,6 +16,7 @@
 
 package android.window;
 
+import android.view.RemoteAnimationDefinition;
 import android.window.ITaskFragmentOrganizer;
 
 /** @hide */
@@ -30,4 +31,17 @@
      * Unregisters a previously registered TaskFragmentOrganizer.
      */
     void unregisterOrganizer(in ITaskFragmentOrganizer organizer);
+
+    /**
+     * Registers remote animations per transition type for the organizer. It will override the
+     * animations if the transition only contains windows that belong to the organized
+     * TaskFragments.
+     */
+    void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
+        in RemoteAnimationDefinition definition);
+
+    /**
+     * Unregisters remote animations per transition type for the organizer.
+     */
+    void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
 }
diff --git a/core/java/android/uwb/SessionHandle.aidl b/core/java/android/window/RemoteTransition.aidl
similarity index 83%
rename from core/java/android/uwb/SessionHandle.aidl
rename to core/java/android/window/RemoteTransition.aidl
index 58a7dbb..f3c3f54 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/core/java/android/window/RemoteTransition.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.uwb;
+package android.window;
 
-parcelable SessionHandle;
+parcelable RemoteTransition;
diff --git a/core/java/android/window/RemoteTransition.java b/core/java/android/window/RemoteTransition.java
new file mode 100644
index 0000000..b243b65
--- /dev/null
+++ b/core/java/android/window/RemoteTransition.java
@@ -0,0 +1,158 @@
+/*
+ * 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents a remote transition animation and information required to run it (eg. the app thread
+ * that needs to be boosted).
+ * @hide
+ */
+@DataClass(genToString = true, genSetters = true, genAidl = true)
+public class RemoteTransition implements Parcelable {
+
+    /** The actual remote-transition interface used to run the transition animation. */
+    private @NonNull IRemoteTransition mRemoteTransition;
+
+    /** Get the IBinder associated with the underlying IRemoteTransition. */
+    public @Nullable IBinder asBinder() {
+        return mRemoteTransition.asBinder();
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/RemoteTransition.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new RemoteTransition.
+     *
+     * @param remoteTransition
+     *   The actual remote-transition interface used to run the transition animation.
+     */
+    @DataClass.Generated.Member
+    public RemoteTransition(
+            @NonNull IRemoteTransition remoteTransition) {
+        this.mRemoteTransition = remoteTransition;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRemoteTransition);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The actual remote-transition interface used to run the transition animation.
+     */
+    @DataClass.Generated.Member
+    public @NonNull IRemoteTransition getRemoteTransition() {
+        return mRemoteTransition;
+    }
+
+    /**
+     * The actual remote-transition interface used to run the transition animation.
+     */
+    @DataClass.Generated.Member
+    public @NonNull RemoteTransition setRemoteTransition(@NonNull IRemoteTransition value) {
+        mRemoteTransition = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRemoteTransition);
+        return this;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "RemoteTransition { " +
+                "remoteTransition = " + mRemoteTransition +
+        " }";
+    }
+
+    @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) { ... }
+
+        dest.writeStrongInterface(mRemoteTransition);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected RemoteTransition(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        IRemoteTransition remoteTransition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+
+        this.mRemoteTransition = remoteTransition;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRemoteTransition);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<RemoteTransition> CREATOR
+            = new Parcelable.Creator<RemoteTransition>() {
+        @Override
+        public RemoteTransition[] newArray(int size) {
+            return new RemoteTransition[size];
+        }
+
+        @Override
+        public RemoteTransition createFromParcel(@NonNull android.os.Parcel in) {
+            return new RemoteTransition(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1630613039043L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/window/RemoteTransition.java",
+            inputSignatures = "private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/window/SizeConfigurationBuckets.java b/core/java/android/window/SizeConfigurationBuckets.java
index 7422f24..f474f0a 100644
--- a/core/java/android/window/SizeConfigurationBuckets.java
+++ b/core/java/android/window/SizeConfigurationBuckets.java
@@ -16,6 +16,7 @@
 
 package android.window;
 
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
 
@@ -25,6 +26,7 @@
 import android.os.Parcelable;
 import android.util.SparseIntArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DataClass;
 
 import java.util.Arrays;
@@ -54,10 +56,24 @@
     @Nullable
     private final int[] mSmallest;
 
+    /** Screen Layout Size (screenLayout & SCREENLAYOUT_SIZE_MASK) buckets */
+    @Nullable
+    private final int[] mScreenLayoutSize;
+
+    /**
+     * Screen Layout Long (screenLayout & SCREENLAYOUT_LONG_MASK) boolean. Only need to know if a
+     * value is set because only two possible buckets, SCREENLAYOUT_LONG_NO and
+     * SCREENLAYOUT_LONG_YES, so if either is set, then any change is a bucket change.
+     */
+    private final boolean mScreenLayoutLongSet;
+
     public SizeConfigurationBuckets(Configuration[] sizeConfigurations) {
         SparseIntArray horizontal = new SparseIntArray();
         SparseIntArray vertical = new SparseIntArray();
         SparseIntArray smallest = new SparseIntArray();
+        SparseIntArray screenLayoutSize = new SparseIntArray();
+        int curScreenLayoutSize;
+        boolean screenLayoutLongSet = false;
         for (int i = sizeConfigurations.length - 1; i >= 0; i--) {
             Configuration config = sizeConfigurations[i];
             if (config.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
@@ -69,23 +85,42 @@
             if (config.smallestScreenWidthDp != Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
                 smallest.put(config.smallestScreenWidthDp, 0);
             }
+            if ((curScreenLayoutSize = config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
+                    != Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
+                screenLayoutSize.put(curScreenLayoutSize, 0);
+            }
+            if (!screenLayoutLongSet && (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK)
+                    != Configuration.SCREENLAYOUT_LONG_UNDEFINED) {
+                screenLayoutLongSet = true;
+            }
         }
         mHorizontal = horizontal.copyKeys();
         mVertical = vertical.copyKeys();
         mSmallest = smallest.copyKeys();
+        mScreenLayoutSize = screenLayoutSize.copyKeys();
+        mScreenLayoutLongSet = screenLayoutLongSet;
     }
 
     /**
      * Get the changes between two configurations but don't count changes in sizes if they don't
-     * cross boundaries that are  important to the app.
+     * cross boundaries that are important to the app.
      *
      * This is a static helper to deal with null `buckets`. When no buckets have been specified,
      * this actually filters out all 3 size-configs. This is legacy behavior.
      */
-    public static int filterDiff(int diff, Configuration oldConfig, Configuration newConfig,
-            @Nullable SizeConfigurationBuckets buckets) {
+    public static int filterDiff(int diff, @NonNull Configuration oldConfig,
+            @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) {
+        final boolean nonSizeLayoutFieldsUnchanged =
+                areNonSizeLayoutFieldsUnchanged(oldConfig.screenLayout, newConfig.screenLayout);
         if (buckets == null) {
-            return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE);
+            // Only unflip CONFIG_SCREEN_LAYOUT if non-size-related  attributes of screen layout do
+            // not change.
+            if (nonSizeLayoutFieldsUnchanged) {
+                return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE
+                        | CONFIG_SCREEN_LAYOUT);
+            } else {
+                return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE);
+            }
         }
         if ((diff & CONFIG_SCREEN_SIZE) != 0) {
             final boolean crosses = buckets.crossesHorizontalSizeThreshold(oldConfig.screenWidthDp,
@@ -103,6 +138,13 @@
                 diff &= ~CONFIG_SMALLEST_SCREEN_SIZE;
             }
         }
+        if ((diff & CONFIG_SCREEN_LAYOUT) != 0 && nonSizeLayoutFieldsUnchanged) {
+            if (!buckets.crossesScreenLayoutSizeThreshold(oldConfig, newConfig)
+                    && !buckets.crossesScreenLayoutLongThreshold(oldConfig.screenLayout,
+                    newConfig.screenLayout)) {
+                diff &= ~CONFIG_SCREEN_LAYOUT;
+            }
+        }
         return diff;
     }
 
@@ -119,6 +161,61 @@
     }
 
     /**
+     * Returns whether a screen layout size threshold has been crossed.
+     */
+    @VisibleForTesting
+    public boolean crossesScreenLayoutSizeThreshold(@NonNull Configuration firstConfig,
+            @NonNull Configuration secondConfig) {
+        // If both the old and new screen layout are equal (both can be undefined), then no
+        // threshold is crossed.
+        if ((firstConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
+                == (secondConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)) {
+            return false;
+        }
+        // Any time the new layout size is smaller than the old layout size, the activity has
+        // crossed a size threshold because layout size represents the smallest possible size the
+        // activity can occupy.
+        if (!secondConfig.isLayoutSizeAtLeast(firstConfig.screenLayout
+                & Configuration.SCREENLAYOUT_SIZE_MASK)) {
+            return true;
+        }
+        // If the new layout size is at least as large as the old layout size, then check if the new
+        // layout size has crossed a threshold.
+        if (mScreenLayoutSize != null) {
+            for (int screenLayoutSize : mScreenLayoutSize) {
+                if (firstConfig.isLayoutSizeAtLeast(screenLayoutSize)
+                        != secondConfig.isLayoutSizeAtLeast(screenLayoutSize)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean crossesScreenLayoutLongThreshold(int firstScreenLayout,
+            int secondScreenLayout) {
+        final int firstScreenLayoutLongValue = firstScreenLayout
+                & Configuration.SCREENLAYOUT_LONG_MASK;
+        final int secondScreenLayoutLongValue = secondScreenLayout
+                & Configuration.SCREENLAYOUT_LONG_MASK;
+        return mScreenLayoutLongSet && firstScreenLayoutLongValue != secondScreenLayoutLongValue;
+    }
+
+    /**
+     * Returns whether non-size related screen layout attributes have changed. If true, then
+     * {@link ActivityInfo#CONFIG_SCREEN_LAYOUT} should not be filtered out in
+     * {@link SizeConfigurationBuckets#filterDiff()} because the non-size related attributes
+     * do not have a bucket range like the size-related attributes of screen layout.
+     */
+    @VisibleForTesting
+    public static boolean areNonSizeLayoutFieldsUnchanged(int oldScreenLayout,
+            int newScreenLayout) {
+        final int nonSizeRelatedFields = Configuration.SCREENLAYOUT_LAYOUTDIR_MASK
+                | Configuration.SCREENLAYOUT_ROUND_MASK | Configuration.SCREENLAYOUT_COMPAT_NEEDED;
+        return (oldScreenLayout & nonSizeRelatedFields) == (newScreenLayout & nonSizeRelatedFields);
+    }
+
+    /**
      * The purpose of this method is to decide whether the activity needs to be relaunched upon
      * changing its size. In most cases the activities don't need to be relaunched, if the resize
      * is small, all the activity content has to do is relayout itself within new bounds. There are
@@ -132,7 +229,8 @@
      * it resizes width from 620dp to 700dp, it won't be relaunched as it stays on the same side
      * of the threshold.
      */
-    private static boolean crossesSizeThreshold(int[] thresholds, int firstDp,
+    @VisibleForTesting
+    public static boolean crossesSizeThreshold(int[] thresholds, int firstDp,
             int secondDp) {
         if (thresholds == null) {
             return false;
@@ -150,12 +248,13 @@
     @Override
     public String toString() {
         return Arrays.toString(mHorizontal) + " " + Arrays.toString(mVertical) + " "
-                + Arrays.toString(mSmallest);
+                + Arrays.toString(mSmallest) + " " + Arrays.toString(mScreenLayoutSize) + " "
+                + mScreenLayoutLongSet;
     }
 
 
 
-    // Code below generated by codegen v1.0.22.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -177,15 +276,25 @@
      *   Vertical (screenHeightDp) buckets
      * @param smallest
      *   Smallest (smallestScreenWidthDp) buckets
+     * @param screenLayoutSize
+     *   Screen Layout Size (screenLayout & SCREENLAYOUT_SIZE_MASK) buckets
+     * @param screenLayoutLongSet
+     *   Screen Layout Long (screenLayout & SCREENLAYOUT_LONG_MASK) boolean. Only need to know if a
+     *   value is set because only two possible buckets, SCREENLAYOUT_LONG_NO and
+     *   SCREENLAYOUT_LONG_YES, so if either is set, then any change is a bucket change.
      */
     @DataClass.Generated.Member
     public SizeConfigurationBuckets(
             @Nullable int[] horizontal,
             @Nullable int[] vertical,
-            @Nullable int[] smallest) {
+            @Nullable int[] smallest,
+            @Nullable int[] screenLayoutSize,
+            boolean screenLayoutLongSet) {
         this.mHorizontal = horizontal;
         this.mVertical = vertical;
         this.mSmallest = smallest;
+        this.mScreenLayoutSize = screenLayoutSize;
+        this.mScreenLayoutLongSet = screenLayoutLongSet;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -214,6 +323,24 @@
         return mSmallest;
     }
 
+    /**
+     * Screen Layout Size (screenLayout & SCREENLAYOUT_SIZE_MASK) buckets
+     */
+    @DataClass.Generated.Member
+    public @Nullable int[] getScreenLayoutSize() {
+        return mScreenLayoutSize;
+    }
+
+    /**
+     * Screen Layout Long (screenLayout & SCREENLAYOUT_LONG_MASK) boolean. Only need to know if a
+     * value is set because only two possible buckets, SCREENLAYOUT_LONG_NO and
+     * SCREENLAYOUT_LONG_YES, so if either is set, then any change is a bucket change.
+     */
+    @DataClass.Generated.Member
+    public boolean isScreenLayoutLongSet() {
+        return mScreenLayoutLongSet;
+    }
+
     @Override
     @DataClass.Generated.Member
     public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
@@ -221,13 +348,16 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
+        if (mScreenLayoutLongSet) flg |= 0x10;
         if (mHorizontal != null) flg |= 0x1;
         if (mVertical != null) flg |= 0x2;
         if (mSmallest != null) flg |= 0x4;
+        if (mScreenLayoutSize != null) flg |= 0x8;
         dest.writeByte(flg);
         if (mHorizontal != null) dest.writeIntArray(mHorizontal);
         if (mVertical != null) dest.writeIntArray(mVertical);
         if (mSmallest != null) dest.writeIntArray(mSmallest);
+        if (mScreenLayoutSize != null) dest.writeIntArray(mScreenLayoutSize);
     }
 
     @Override
@@ -242,13 +372,17 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         byte flg = in.readByte();
+        boolean screenLayoutLongSet = (flg & 0x10) != 0;
         int[] horizontal = (flg & 0x1) == 0 ? null : in.createIntArray();
         int[] vertical = (flg & 0x2) == 0 ? null : in.createIntArray();
         int[] smallest = (flg & 0x4) == 0 ? null : in.createIntArray();
+        int[] screenLayoutSize = (flg & 0x8) == 0 ? null : in.createIntArray();
 
         this.mHorizontal = horizontal;
         this.mVertical = vertical;
         this.mSmallest = smallest;
+        this.mScreenLayoutSize = screenLayoutSize;
+        this.mScreenLayoutLongSet = screenLayoutLongSet;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -268,10 +402,10 @@
     };
 
     @DataClass.Generated(
-            time = 1615845864280L,
-            codegenVersion = "1.0.22",
+            time = 1628273704583L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/window/SizeConfigurationBuckets.java",
-            inputSignatures = "private final @android.annotation.Nullable int[] mHorizontal\nprivate final @android.annotation.Nullable int[] mVertical\nprivate final @android.annotation.Nullable int[] mSmallest\npublic static  int filterDiff(int,android.content.res.Configuration,android.content.res.Configuration,android.window.SizeConfigurationBuckets)\nprivate  boolean crossesHorizontalSizeThreshold(int,int)\nprivate  boolean crossesVerticalSizeThreshold(int,int)\nprivate  boolean crossesSmallestSizeThreshold(int,int)\nprivate static  boolean crossesSizeThreshold(int[],int,int)\npublic @java.lang.Override java.lang.String toString()\nclass SizeConfigurationBuckets extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true)")
+            inputSignatures = "private final @android.annotation.Nullable int[] mHorizontal\nprivate final @android.annotation.Nullable int[] mVertical\nprivate final @android.annotation.Nullable int[] mSmallest\nprivate final @android.annotation.Nullable int[] mScreenLayoutSize\nprivate final  boolean mScreenLayoutLongSet\npublic static  int filterDiff(int,android.content.res.Configuration,android.content.res.Configuration,android.window.SizeConfigurationBuckets)\nprivate  boolean crossesHorizontalSizeThreshold(int,int)\nprivate  boolean crossesVerticalSizeThreshold(int,int)\nprivate  boolean crossesSmallestSizeThreshold(int,int)\npublic @com.android.internal.annotations.VisibleForTesting boolean crossesScreenLayoutSizeThreshold(android.content.res.Configuration,android.content.res.Configuration)\nprivate  boolean crossesScreenLayoutLongThreshold(int,int)\npublic static @com.android.internal.annotations.VisibleForTesting boolean areNonSizeLayoutFieldsUnchanged(int,int)\npublic static @com.android.internal.annotations.VisibleForTesting boolean crossesSizeThreshold(int[],int,int)\npublic @java.lang.Override java.lang.String toString()\nclass SizeConfigurationBuckets extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index acf20d7..f14294e 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -59,6 +59,7 @@
 
 import java.time.Duration;
 import java.time.Instant;
+import java.util.function.Consumer;
 
 /**
  * <p>The view which allows an activity to customize its splash screen exit animation.</p>
@@ -144,6 +145,7 @@
         private Bitmap mParceledBrandingBitmap;
         private Instant mIconAnimationStart;
         private Duration mIconAnimationDuration;
+        private Consumer<Runnable> mUiThreadInitTask;
 
         public Builder(@NonNull Context context) {
             mContext = context;
@@ -232,6 +234,15 @@
         }
 
         /**
+         * Set the Runnable that can receive the task which should be executed on UI thread.
+         * @param uiThreadInitTask
+         */
+        public Builder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
+            mUiThreadInitTask = uiThreadInitTask;
+            return this;
+        }
+
+        /**
          * Set the Drawable object and size for the branding view.
          */
         public Builder setBrandingDrawable(@Nullable Drawable branding, int width, int height) {
@@ -262,7 +273,11 @@
             // center icon
             if (mIconDrawable instanceof SplashScreenView.IconAnimateListener
                     || mSurfacePackage != null) {
-                view.mIconView = createSurfaceView(view);
+                if (mUiThreadInitTask != null) {
+                    mUiThreadInitTask.accept(() -> view.mIconView = createSurfaceView(view));
+                } else {
+                    view.mIconView = createSurfaceView(view);
+                }
                 view.initIconAnimation(mIconDrawable,
                         mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
                 view.mIconAnimationStart = mIconAnimationStart;
@@ -316,7 +331,9 @@
         }
 
         private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
-            final SurfaceView surfaceView = new SurfaceView(view.getContext());
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SplashScreenView#createSurfaceView");
+            final Context viewContext = view.getContext();
+            final SurfaceView surfaceView = new SurfaceView(viewContext);
             surfaceView.setPadding(0, 0, 0, 0);
             surfaceView.setBackground(mIconBackground);
             if (mSurfacePackage == null) {
@@ -326,10 +343,10 @@
                                     + Thread.currentThread().getId());
                 }
 
-                SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext,
-                        mContext.getDisplay(),
+                SurfaceControlViewHost viewHost = new SurfaceControlViewHost(viewContext,
+                        viewContext.getDisplay(),
                         surfaceView.getHostToken());
-                ImageView imageView = new ImageView(mContext);
+                ImageView imageView = new ImageView(viewContext);
                 imageView.setBackground(mIconDrawable);
                 viewHost.setView(imageView, mIconSize, mIconSize);
                 SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage();
@@ -360,6 +377,7 @@
 
             view.addView(surfaceView);
             view.mSurfaceView = surfaceView;
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return surfaceView;
         }
     }
@@ -531,17 +549,14 @@
 
     private void releaseAnimationSurfaceHost() {
         if (mSurfaceHost != null && !mIsCopied) {
-            final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost;
+            if (DEBUG) {
+                Log.d(TAG,
+                        "Shell removed splash screen."
+                                + " Releasing SurfaceControlViewHost on thread #"
+                                + Thread.currentThread().getId());
+            }
+            releaseIconHost(mSurfaceHost);
             mSurfaceHost = null;
-            finalSurfaceHost.getView().post(() -> {
-                if (DEBUG) {
-                    Log.d(TAG,
-                            "Shell removed splash screen."
-                                    + " Releasing SurfaceControlViewHost on thread #"
-                                    + Thread.currentThread().getId());
-                }
-                finalSurfaceHost.release();
-            });
         } else if (mSurfacePackage != null && mSurfaceHost == null) {
             mSurfacePackage = null;
             mClientCallback.sendResult(null);
@@ -549,6 +564,18 @@
     }
 
     /**
+     * Release the host which hold the SurfaceView of the icon.
+     * @hide
+     */
+    public static void releaseIconHost(SurfaceControlViewHost host) {
+        final Drawable background = host.getView().getBackground();
+        if (background instanceof SplashScreenView.IconAnimateListener) {
+            ((SplashScreenView.IconAnimateListener) background).stopAnimation();
+        }
+        host.release();
+    }
+
+    /**
      * Called when this view is attached to an activity. This also makes SystemUI colors
      * transparent so the content of splash screen view can draw fully.
      *
@@ -639,6 +666,11 @@
          * @return true if this drawable object can also be animated and it can be played now.
          */
         boolean prepareAnimate(long duration, Runnable startListener);
+
+        /**
+         * Stop animation.
+         */
+        void stopAnimation();
     }
 
     /**
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index dac420b..b55372b 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -55,8 +55,8 @@
     /** Whether the TaskFragment contains any child Window Container. */
     private final boolean mIsEmpty;
 
-    /** Whether the TaskFragment contains any running Activity. */
-    private final boolean mHasRunningActivity;
+    /** The number of the running activities in the TaskFragment. */
+    private final int mRunningActivityCount;
 
     /** Whether this TaskFragment is visible on the window hierarchy. */
     private final boolean mIsVisible;
@@ -74,13 +74,13 @@
     /** @hide */
     public TaskFragmentInfo(
             @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
-            @NonNull Configuration configuration, boolean isEmpty, boolean hasRunningActivity,
+            @NonNull Configuration configuration, boolean isEmpty, int runningActivityCount,
             boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent) {
         mFragmentToken = requireNonNull(fragmentToken);
         mToken = requireNonNull(token);
         mConfiguration.setTo(configuration);
         mIsEmpty = isEmpty;
-        mHasRunningActivity = hasRunningActivity;
+        mRunningActivityCount = runningActivityCount;
         mIsVisible = isVisible;
         mActivities.addAll(activities);
         mPositionInParent = requireNonNull(positionInParent);
@@ -106,7 +106,11 @@
     }
 
     public boolean hasRunningActivity() {
-        return mHasRunningActivity;
+        return mRunningActivityCount > 0;
+    }
+
+    public int getRunningActivityCount() {
+        return mRunningActivityCount;
     }
 
     public boolean isVisible() {
@@ -141,7 +145,7 @@
         return mFragmentToken.equals(that.mFragmentToken)
                 && mToken.equals(that.mToken)
                 && mIsEmpty == that.mIsEmpty
-                && mHasRunningActivity == that.mHasRunningActivity
+                && mRunningActivityCount == that.mRunningActivityCount
                 && mIsVisible == that.mIsVisible
                 && getWindowingMode() == that.getWindowingMode()
                 && mActivities.equals(that.mActivities)
@@ -153,7 +157,7 @@
         mToken = in.readTypedObject(WindowContainerToken.CREATOR);
         mConfiguration.readFromParcel(in);
         mIsEmpty = in.readBoolean();
-        mHasRunningActivity = in.readBoolean();
+        mRunningActivityCount = in.readInt();
         mIsVisible = in.readBoolean();
         in.readBinderList(mActivities);
         mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
@@ -166,7 +170,7 @@
         dest.writeTypedObject(mToken, flags);
         mConfiguration.writeToParcel(dest, flags);
         dest.writeBoolean(mIsEmpty);
-        dest.writeBoolean(mHasRunningActivity);
+        dest.writeInt(mRunningActivityCount);
         dest.writeBoolean(mIsVisible);
         dest.writeBinderList(mActivities);
         dest.writeTypedObject(mPositionInParent, flags);
@@ -192,7 +196,7 @@
                 + " fragmentToken=" + mFragmentToken
                 + " token=" + mToken
                 + " isEmpty=" + mIsEmpty
-                + " hasRunningActivity=" + mHasRunningActivity
+                + " runningActivityCount=" + mRunningActivityCount
                 + " isVisible=" + mIsVisible
                 + " positionInParent=" + mPositionInParent
                 + "}";
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index f22f0b2..337c5a1 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.view.RemoteAnimationDefinition;
 
 import java.util.concurrent.Executor;
 
@@ -90,6 +91,34 @@
         }
     }
 
+    /**
+     * Registers remote animations per transition type for the organizer. It will override the
+     * animations if the transition only contains windows that belong to the organized
+     * TaskFragments.
+     * @hide
+     */
+    @CallSuper
+    public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
+        try {
+            getController().registerRemoteAnimations(mInterface, definition);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregisters remote animations per transition type for the organizer.
+     * @hide
+     */
+    @CallSuper
+    public void unregisterRemoteAnimations() {
+        try {
+            getController().unregisterRemoteAnimations(mInterface);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** Called when a TaskFragment is created and organized by this organizer. */
     public void onTaskFragmentAppeared(
             @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {}
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 34facc4..db15145 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -59,6 +59,9 @@
     /** All flags must be set on a transition. */
     public @WindowManager.TransitionFlags int mFlags = 0;
 
+    /** All flags must NOT be set on a transition. */
+    public @WindowManager.TransitionFlags int mNotFlags = 0;
+
     /**
      * A list of required changes. To pass, a transition must meet all requirements.
      */
@@ -70,6 +73,7 @@
     private TransitionFilter(Parcel in) {
         mTypeSet = in.createIntArray();
         mFlags = in.readInt();
+        mNotFlags = in.readInt();
         mRequirements = in.createTypedArray(Requirement.CREATOR);
     }
 
@@ -89,6 +93,9 @@
         if ((info.getFlags() & mFlags) != mFlags) {
             return false;
         }
+        if ((info.getFlags() & mNotFlags) != 0) {
+            return false;
+        }
         // Make sure info meets all of the requirements.
         if (mRequirements != null) {
             for (int i = 0; i < mRequirements.length; ++i) {
@@ -106,6 +113,7 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeIntArray(mTypeSet);
         dest.writeInt(mFlags);
+        dest.writeInt(mNotFlags);
         dest.writeTypedArray(mRequirements, flags);
     }
 
@@ -139,6 +147,7 @@
             }
         }
         sb.append("] flags=0x" + Integer.toHexString(mFlags));
+        sb.append("] notFlags=0x" + Integer.toHexString(mNotFlags));
         sb.append(" checks=[");
         if (mRequirements != null) {
             for (int i = 0; i < mRequirements.length; ++i) {
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index b7de7b8..c2ffc03 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -23,8 +23,10 @@
 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_FLAG_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -94,8 +96,16 @@
     /** 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 << 7;
+    public static final int FLAG_FIRST_CUSTOM = 1 << 8;
 
     /** @hide */
     @IntDef(prefix = { "FLAG_" }, value = {
@@ -107,6 +117,7 @@
             FLAG_IS_VOICE_INTERACTION,
             FLAG_IS_DISPLAY,
             FLAG_OCCLUDES_KEYGUARD,
+            FLAG_DISPLAY_HAS_ALERT_WINDOWS,
             FLAG_FIRST_CUSTOM
     })
     public @interface ChangeFlags {}
@@ -209,6 +220,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;
@@ -235,6 +250,13 @@
         mChanges.add(change);
     }
 
+    /**
+     * Whether this transition includes keyguard going away.
+     */
+    public boolean isKeyguardGoingAway() {
+        return (mFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -290,6 +312,9 @@
         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");
         }
@@ -335,8 +360,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;
@@ -354,8 +381,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. */
@@ -396,12 +425,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() {
@@ -465,6 +507,10 @@
             return mTaskInfo;
         }
 
+        public boolean getAllowEnterPip() {
+            return mAllowEnterPip;
+        }
+
         public int getStartRotation() {
             return mStartRotation;
         }
@@ -473,6 +519,11 @@
             return mEndRotation;
         }
 
+        /** @return the rotation animation. */
+        public int getRotationAnimation() {
+            return mRotationAnimation;
+        }
+
         /** @hide */
         @Override
         public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -485,8 +536,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
@@ -514,7 +567,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/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java
index cc493ab..f770731 100644
--- a/core/java/android/window/TransitionRequestInfo.java
+++ b/core/java/android/window/TransitionRequestInfo.java
@@ -40,11 +40,11 @@
     private @Nullable ActivityManager.RunningTaskInfo mTriggerTask;
 
     /** If non-null, a remote-transition associated with the source of this transition. */
-    private @Nullable IRemoteTransition mRemoteTransition;
+    private @Nullable RemoteTransition mRemoteTransition;
 
 
 
-    // Code below generated by codegen v1.0.22.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -72,7 +72,7 @@
     public TransitionRequestInfo(
             @WindowManager.TransitionType int type,
             @Nullable ActivityManager.RunningTaskInfo triggerTask,
-            @Nullable IRemoteTransition remoteTransition) {
+            @Nullable RemoteTransition remoteTransition) {
         this.mType = type;
         com.android.internal.util.AnnotationValidations.validate(
                 WindowManager.TransitionType.class, null, mType);
@@ -103,7 +103,7 @@
      * If non-null, a remote-transition associated with the source of this transition.
      */
     @DataClass.Generated.Member
-    public @Nullable IRemoteTransition getRemoteTransition() {
+    public @Nullable RemoteTransition getRemoteTransition() {
         return mRemoteTransition;
     }
 
@@ -121,7 +121,7 @@
      * If non-null, a remote-transition associated with the source of this transition.
      */
     @DataClass.Generated.Member
-    public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull IRemoteTransition value) {
+    public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull RemoteTransition value) {
         mRemoteTransition = value;
         return this;
     }
@@ -151,7 +151,7 @@
         dest.writeByte(flg);
         dest.writeInt(mType);
         if (mTriggerTask != null) dest.writeTypedObject(mTriggerTask, flags);
-        if (mRemoteTransition != null) dest.writeStrongInterface(mRemoteTransition);
+        if (mRemoteTransition != null) dest.writeTypedObject(mRemoteTransition, flags);
     }
 
     @Override
@@ -168,7 +168,7 @@
         byte flg = in.readByte();
         int type = in.readInt();
         ActivityManager.RunningTaskInfo triggerTask = (flg & 0x2) == 0 ? null : (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
-        IRemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+        RemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR);
 
         this.mType = type;
         com.android.internal.util.AnnotationValidations.validate(
@@ -194,10 +194,10 @@
     };
 
     @DataClass.Generated(
-            time = 1610060387917L,
-            codegenVersion = "1.0.22",
+            time = 1629321632222L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java",
-            inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.IRemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
+            inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.RemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 342df4f..387837d 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -516,11 +516,13 @@
      */
     @NonNull
     public WindowContainerTransaction setAdjacentTaskFragments(
-            @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) {
+            @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2,
+            @Nullable TaskFragmentAdjacentOptions options) {
         final HierarchyOp hierarchyOp =
                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
                         .setContainer(fragmentToken1)
                         .setReparentContainer(fragmentToken2)
+                        .setLaunchOptions(options != null ? options.toBundle() : null)
                         .build();
         mHierarchyOps.add(hierarchyOp);
         return this;
@@ -1298,4 +1300,52 @@
             }
         }
     }
+
+    /**
+     * Helper class for building an options Bundle that can be used to set adjacent rules of
+     * TaskFragments.
+     * @hide
+     */
+    public static class TaskFragmentAdjacentOptions {
+        private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL =
+                "android:transaction.adjacent.option.delay_primary_removal";
+        private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL =
+                "android:transaction.adjacent.option.delay_secondary_removal";
+
+        private boolean mDelayPrimaryLastActivityRemoval;
+        private boolean mDelaySecondaryLastActivityRemoval;
+
+        public TaskFragmentAdjacentOptions() {
+        }
+
+        public TaskFragmentAdjacentOptions(@NonNull Bundle bundle) {
+            mDelayPrimaryLastActivityRemoval = bundle.getBoolean(
+                    DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL);
+            mDelaySecondaryLastActivityRemoval = bundle.getBoolean(
+                    DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL);
+        }
+
+        public void setDelayPrimaryLastActivityRemoval(boolean delay) {
+            mDelayPrimaryLastActivityRemoval = delay;
+        }
+
+        public void setDelaySecondaryLastActivityRemoval(boolean delay) {
+            mDelaySecondaryLastActivityRemoval = delay;
+        }
+
+        public boolean isDelayPrimaryLastActivityRemoval() {
+            return mDelayPrimaryLastActivityRemoval;
+        }
+
+        public boolean isDelaySecondaryLastActivityRemoval() {
+            return mDelaySecondaryLastActivityRemoval;
+        }
+
+        Bundle toBundle() {
+            final Bundle b = new Bundle();
+            b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval);
+            b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval);
+            return b;
+        }
+    }
 }
diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java
index 5d40085..cfccb71 100644
--- a/core/java/android/window/WindowContext.java
+++ b/core/java/android/window/WindowContext.java
@@ -26,6 +26,7 @@
 import android.content.ContextWrapper;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.view.Display;
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -42,29 +43,33 @@
  * @hide
  */
 @UiContext
-public class WindowContext extends ContextWrapper {
+public class WindowContext extends ContextWrapper implements WindowProvider {
     private final WindowManager mWindowManager;
-    private final @WindowManager.LayoutParams.WindowType int mType;
-    private final @Nullable Bundle mOptions;
+    @WindowManager.LayoutParams.WindowType
+    private final int mType;
+    @Nullable
+    private final Bundle mOptions;
     private final ComponentCallbacksController mCallbacksController =
             new ComponentCallbacksController();
     private final WindowContextController mController;
 
     /**
-     * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
-     * the token.
+     * Default implementation of {@link WindowContext}
+     * <p>
+     * Note that the users should call {@link Context#createWindowContext(Display, int, Bundle)}
+     * to create a {@link WindowContext} instead of using this constructor
+     * </p><p>
+     * Example usage:
+     * <pre class="prettyprint">
+     * Bundle options = new Bundle();
+     * options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
+     * Context windowContext = context.createWindowContext(display, windowType, options);
+     * </pre></p>
      *
-     * @param base Base {@link Context} for this new instance.
-     * @param type Window type to be used with this context.
-     * @param options A bundle used to pass window-related options. For example, on device with
-     *                multiple DisplayAreaGroups, one may specify the RootDisplayArea for the window
-     *                using {@link DisplayAreaOrganizer#KEY_ROOT_DISPLAY_AREA_ID} in the options.
-     *                Example usage:
-     *                Bundle options = new Bundle();
-     *                options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
-     *                Context windowContext = context.createWindowContext(display, type, options);
+     * @param base    Base {@link Context} for this new instance.
+     * @param type    Window type to be used with this context.
+     * @param options A bundle used to pass window-related options.
      * @see DisplayAreaInfo#rootDisplayAreaId
-     * @hide
      */
     public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
         super(base);
@@ -110,10 +115,13 @@
 
     @Override
     public void destroy() {
-        mCallbacksController.clearCallbacks();
-        // Called to the base ContextImpl to do final clean-up.
-        getBaseContext().destroy();
-        Reference.reachabilityFence(this);
+        try {
+            mCallbacksController.clearCallbacks();
+            // Called to the base ContextImpl to do final clean-up.
+            getBaseContext().destroy();
+        } finally {
+            Reference.reachabilityFence(this);
+        }
     }
 
     @Override
@@ -130,4 +138,15 @@
     void dispatchConfigurationChanged(@NonNull Configuration newConfig) {
         mCallbacksController.dispatchConfigurationChanged(newConfig);
     }
+
+    @Override
+    public int getWindowType() {
+        return mType;
+    }
+
+    @Nullable
+    @Override
+    public Bundle getWindowContextOptions() {
+        return mOptions;
+    }
 }
diff --git a/core/java/android/window/WindowInfosListener.java b/core/java/android/window/WindowInfosListener.java
new file mode 100644
index 0000000..4376e3e
--- /dev/null
+++ b/core/java/android/window/WindowInfosListener.java
@@ -0,0 +1,63 @@
+/*
+ * 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.window;
+
+import android.view.InputWindowHandle;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Listener for getting {@link InputWindowHandle} updates from SurfaceFlinger.
+ * @hide
+ */
+public abstract class WindowInfosListener {
+    private final long mNativeListener;
+
+    public WindowInfosListener() {
+        NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced(
+                WindowInfosListener.class.getClassLoader(), nativeGetFinalizer());
+
+        mNativeListener = nativeCreate(this);
+        registry.registerNativeAllocation(this, mNativeListener);
+    }
+
+    /**
+     * Called when WindowInfos in SurfaceFlinger have changed.
+     * @param windowHandles Reverse Z ordered array of window information that was on screen,
+     *                      where the first value is the topmost window.
+     */
+    public abstract void onWindowInfosChanged(InputWindowHandle[] windowHandles);
+
+    /**
+     * Register the WindowInfosListener.
+     */
+    public void register() {
+        nativeRegister(mNativeListener);
+    }
+
+    /**
+     * Unregisters the WindowInfosListener.
+     */
+    public void unregister() {
+        nativeUnregister(mNativeListener);
+    }
+
+    private static native long nativeCreate(WindowInfosListener thiz);
+    private static native void nativeRegister(long ptr);
+    private static native void nativeUnregister(long ptr);
+    private static native long nativeGetFinalizer();
+}
diff --git a/core/java/android/window/WindowProvider.java b/core/java/android/window/WindowProvider.java
new file mode 100644
index 0000000..b078b93
--- /dev/null
+++ b/core/java/android/window/WindowProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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.window;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.view.WindowManager.LayoutParams.WindowType;
+
+/**
+ * An interface to provide a non-activity window.
+ * Examples are {@link WindowContext} and {@link WindowProviderService}.
+ *
+ * @hide
+ */
+public interface WindowProvider {
+    /** @hide */
+    String KEY_IS_WINDOW_PROVIDER_SERVICE = "android.windowContext.isWindowProviderService";
+
+    /** Gets the window type of this provider */
+    @WindowType
+    int getWindowType();
+
+    /** Gets the launch options of this provider */
+    @Nullable
+    Bundle getWindowContextOptions();
+}
diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java
index 5171adf..f8484d1 100644
--- a/core/java/android/window/WindowProviderService.java
+++ b/core/java/android/window/WindowProviderService.java
@@ -42,21 +42,39 @@
  * {@link WindowContext}, but is represented as {@link Service}.
  *
  * @see android.inputmethodservice.InputMethodService
- * @see android.accessibilityservice.AccessibilityService
  *
  * @hide
  */
 @TestApi
 @UiContext
-public abstract class WindowProviderService extends Service {
+public abstract class WindowProviderService extends Service implements WindowProvider {
 
+    private final Bundle mOptions;
     private final WindowTokenClient mWindowToken = new WindowTokenClient();
     private final WindowContextController mController = new WindowContextController(mWindowToken);
     private WindowManager mWindowManager;
     private boolean mInitialized;
 
     /**
-     * Returns the type of this {@link WindowProviderService}.
+     * Returns {@code true} if the {@code windowContextOptions} declares that it is a
+     * {@link WindowProviderService}.
+     *
+     * @hide
+     */
+    public static boolean isWindowProviderService(@Nullable Bundle windowContextOptions) {
+        if (windowContextOptions == null) {
+            return false;
+        }
+        return (windowContextOptions.getBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, false));
+    }
+
+    public WindowProviderService() {
+        mOptions = new Bundle();
+        mOptions.putBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, true);
+    }
+
+    /**
+     * Returns the window type of this {@link WindowProviderService}.
      * Each inheriting class must implement this method to provide the type of the window. It is
      * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)}
      *
@@ -68,15 +86,24 @@
     @SuppressLint("OnNameExpected")
     // Suppress the lint because it is not a callback and users should provide window type
     // so we cannot make it final.
-    public abstract @WindowType int getWindowType();
+    @WindowType
+    @Override
+    public abstract int getWindowType();
 
     /**
      * Returns the option of this {@link WindowProviderService}.
-     * Default is {@code null}. The inheriting class can implement this method to provide the
-     * customization {@code option} of the window. It is used similar to {@code options} of
-     * {@link Context#createWindowContext(int, Bundle)}
-     *
-     * @see Context#createWindowContext(int, Bundle)
+     * <p>
+     * The inheriting class can implement this method to provide the customization {@code option} of
+     * the window, but must be based on this method's returned value.
+     * It is used similar to {@code options} of {@link Context#createWindowContext(int, Bundle)}
+     * </p>
+     * <pre class="prettyprint">
+     * public Bundle getWindowContextOptions() {
+     *     final Bundle options = super.getWindowContextOptions();
+     *     options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
+     *     return options;
+     * }
+     * </pre>
      *
      * @hide
      */
@@ -85,8 +112,10 @@
     // Suppress the lint because it is not a callback and users may override this API to provide
     // launch option. Also, the return value of this API is null by default.
     @Nullable
+    @CallSuper
+    @Override
     public Bundle getWindowContextOptions() {
-        return null;
+        return mOptions;
     }
 
     /**
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 284b4b9..f3e3859 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -94,6 +94,8 @@
         onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
     }
 
+    // TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService
+    //  are inherited from WindowProvider.
     /**
      * Called when {@link Configuration} updates from the server side receive.
      *
diff --git a/core/java/com/android/ims/internal/uce/common/CapInfo.java b/core/java/com/android/ims/internal/uce/common/CapInfo.java
index bca647a..f5c4b1f 100644
--- a/core/java/com/android/ims/internal/uce/common/CapInfo.java
+++ b/core/java/com/android/ims/internal/uce/common/CapInfo.java
@@ -20,6 +20,10 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Bundle;
+
+import java.util.Map;
+import java.util.HashMap;
 
 /** Class for capability discovery information.
  *  @hide */
@@ -88,6 +92,95 @@
     /** Time used to compute when to query again. */
     private long mCapTimestamp = 0;
 
+    private Map<String, String> mCapInfoMap = new HashMap<String, String>();
+
+    /** IM session feature tag key. */
+    public static final String INSTANT_MSG =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\"";
+    /** File transfer feature tag key. */
+    public static final String FILE_TRANSFER =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.ft\"";
+    /** File transfer Thumbnail feature tag key. */
+    public static final String FILE_TRANSFER_THUMBNAIL =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftthumb\"";
+    /** File transfer Store and forward feature tag key. */
+    public static final String FILE_TRANSFER_SNF =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftstandfw\"";
+    /** File transfer HTTP feature tag key. */
+    public static final String FILE_TRANSFER_HTTP =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"";
+    /** Image sharing feature tag key. */
+    public static final String IMAGE_SHARE =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-is\"";
+    /** Video sharing during a CS call feature tag key-- IR-74. */
+    public static final String VIDEO_SHARE_DURING_CS = "+g.3gpp.cs-voice";
+    /** Video sharing outside of voice call feature tag key-- IR-84. */
+    public static final String VIDEO_SHARE =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-vs\"";
+    /** Social presence feature tag key. */
+    public static final String SOCIAL_PRESENCE =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.sp\"";
+    /** Presence discovery feature tag key. */
+    public static final String CAPDISC_VIA_PRESENCE =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.dp\"";
+    /** IP voice call feature tag key (IR-92/IR-58). */
+    public static final String IP_VOICE =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"";
+    /** IP video call feature tag key (IR-92/IR-58). */
+    public static final String IP_VIDEO =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\";video";
+    /** IP Geo location Pull using File Transfer feature tag key. */
+    public static final String GEOPULL_FT =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopullft\"";
+    /** IP Geo location Pull feature tag key. */
+    public static final String GEOPULL =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopull\"";
+    /** IP Geo location Push feature tag key. */
+    public static final String GEOPUSH =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\"";
+    /** Standalone messaging feature tag key. */
+    public static final String STANDALONE_MSG =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg;" +
+      "urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\"";
+    /** Full Store and Forward Group Chat information feature tag key. */
+    public static final String FULL_SNF_GROUPCHAT =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fullsfgroupchat\"";
+    /** RCS IP Voice call feature tag key.  */
+    public static final String RCS_IP_VOICE_CALL =
+      "+g.gsma.rcs.ipcall";
+    /** RCS IP Video call feature tag key.  */
+    public static final String RCS_IP_VIDEO_CALL =
+      "+g.gsma.rcs.ipvideocall";
+    /** RCS IP Video only call feature tag key.  */
+    public static final String RCS_IP_VIDEO_ONLY_CALL =
+      "+g.gsma.rcs.ipvideoonlycall";
+    /** IP Geo location Push using SMS feature tag key. */
+    public static final String GEOSMS =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.geosms\"";
+    /** RCS call composer feature tag key. */
+    public static final String CALLCOMPOSER =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.callcomposer\"";
+    /** RCS post-call feature tag key. */
+    public static final String POSTCALL =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.callunanswered\"";
+    /** Shared map feature tag key. */
+    public static final String SHAREDMAP =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.sharedmap\"";
+    /** Shared Sketch feature tag key. */
+    public static final String SHAREDSKETCH =
+      "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.sharedsketch\"";
+    /** Chatbot communication feature tag key. */
+    public static final String CHATBOT =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.chatbot\"";
+    /** Chatbot role feature tag key. */
+    public static final String CHATBOTROLE = "+g.gsma.rcs.isbot";
+    /** Standalone Chatbot communication feature tag key. */
+    public static final String STANDALONE_CHATBOT =
+      "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot.sa\"";
+    /** MMtel based call composer feature tag key. */
+    public static final String MMTEL_CALLCOMPOSER = "+g.gsma.callcomposer";
+
+
 
     /**
      * Constructor for the CapInfo class.
@@ -99,6 +192,7 @@
 
     /**
      * Checks whether IM is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isImSupported() {
@@ -107,6 +201,7 @@
 
     /**
      * Sets IM as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setImSupported(boolean imSupported) {
@@ -115,6 +210,7 @@
 
     /**
      * Checks whether FT Thumbnail is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isFtThumbSupported() {
@@ -123,16 +219,16 @@
 
     /**
      * Sets FT thumbnail as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setFtThumbSupported(boolean ftThumbSupported) {
         this.mFtThumbSupported = ftThumbSupported;
     }
 
-
-
     /**
      * Checks whether FT Store and Forward is supported
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isFtSnFSupported() {
@@ -141,6 +237,7 @@
 
     /**
      * Sets FT Store and Forward as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setFtSnFSupported(boolean  ftSnFSupported) {
@@ -149,6 +246,7 @@
 
    /**
     * Checks whether File transfer HTTP is supported.
+    * @deprecated Use {@link #isCapabilitySupported(String)} instead.
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean isFtHttpSupported() {
@@ -157,6 +255,7 @@
 
    /**
     * Sets File transfer HTTP as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void setFtHttpSupported(boolean  ftHttpSupported) {
@@ -165,6 +264,7 @@
 
     /**
      * Checks whether FT is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isFtSupported() {
@@ -173,6 +273,7 @@
 
     /**
      * Sets FT as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setFtSupported(boolean ftSupported) {
@@ -181,6 +282,7 @@
 
     /**
      * Checks whether IS is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isIsSupported() {
@@ -189,6 +291,7 @@
 
     /**
      * Sets IS as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setIsSupported(boolean isSupported) {
@@ -197,6 +300,7 @@
 
     /**
      * Checks whether video sharing is supported during a CS call.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isVsDuringCSSupported() {
@@ -204,8 +308,9 @@
     }
 
     /**
-     *  Sets video sharing as supported or not supported during a CS
-     *  call.
+     * Sets video sharing as supported or not supported during a CS
+     * call.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setVsDuringCSSupported(boolean vsDuringCSSupported) {
@@ -213,8 +318,9 @@
     }
 
     /**
-     *  Checks whether video sharing outside a voice call is
-     *   supported.
+     * Checks whether video sharing outside a voice call is
+     *  supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isVsSupported() {
@@ -223,6 +329,7 @@
 
     /**
      * Sets video sharing as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setVsSupported(boolean vsSupported) {
@@ -231,6 +338,7 @@
 
     /**
      * Checks whether social presence is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isSpSupported() {
@@ -239,6 +347,7 @@
 
     /**
      * Sets social presence as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setSpSupported(boolean spSupported) {
@@ -248,6 +357,7 @@
     /**
      * Checks whether capability discovery via presence is
      * supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isCdViaPresenceSupported() {
@@ -257,6 +367,7 @@
     /**
      * Sets capability discovery via presence as supported or not
      * supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setCdViaPresenceSupported(boolean cdViaPresenceSupported) {
@@ -265,6 +376,7 @@
 
     /**
      * Checks whether IP voice call is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isIpVoiceSupported() {
@@ -273,6 +385,7 @@
 
     /**
      * Sets IP voice call as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setIpVoiceSupported(boolean ipVoiceSupported) {
@@ -281,6 +394,7 @@
 
     /**
      * Checks whether IP video call is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isIpVideoSupported() {
@@ -289,6 +403,7 @@
 
     /**
      * Sets IP video call as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setIpVideoSupported(boolean ipVideoSupported) {
@@ -298,6 +413,7 @@
    /**
     * Checks whether Geo location Pull using File Transfer is
     * supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean isGeoPullFtSupported() {
@@ -307,6 +423,7 @@
    /**
     * Sets Geo location Pull using File Transfer as supported or
     * not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void setGeoPullFtSupported(boolean geoPullFtSupported) {
@@ -315,6 +432,7 @@
 
     /**
      * Checks whether Geo Pull is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isGeoPullSupported() {
@@ -323,6 +441,7 @@
 
     /**
      * Sets Geo Pull as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setGeoPullSupported(boolean geoPullSupported) {
@@ -331,6 +450,7 @@
 
     /**
      * Checks whether Geo Push is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isGeoPushSupported() {
@@ -339,6 +459,7 @@
 
     /**
      * Sets Geo Push as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setGeoPushSupported(boolean geoPushSupported) {
@@ -347,6 +468,7 @@
 
     /**
      * Checks whether short messaging is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isSmSupported() {
@@ -355,6 +477,7 @@
 
     /**
      * Sets short messaging as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setSmSupported(boolean smSupported) {
@@ -363,22 +486,32 @@
 
     /**
      * Checks whether store/forward and group chat are supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isFullSnFGroupChatSupported() {
         return mFullSnFGroupChatSupported;
     }
 
+    /**
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isRcsIpVoiceCallSupported() {
         return mRcsIpVoiceCallSupported;
     }
 
+    /**
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isRcsIpVideoCallSupported() {
         return mRcsIpVideoCallSupported;
     }
 
+    /**
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isRcsIpVideoOnlyCallSupported() {
         return mRcsIpVideoOnlyCallSupported;
@@ -386,20 +519,32 @@
 
     /**
      * Sets store/forward and group chat supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setFullSnFGroupChatSupported(boolean fullSnFGroupChatSupported) {
         this.mFullSnFGroupChatSupported = fullSnFGroupChatSupported;
     }
 
+    /**
+     * @deprecated Use {@link #addCapability(String, String)} instead.
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setRcsIpVoiceCallSupported(boolean rcsIpVoiceCallSupported) {
         this.mRcsIpVoiceCallSupported = rcsIpVoiceCallSupported;
     }
+
+    /**
+     * @deprecated Use {@link #addCapability(String, String)} instead.
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setRcsIpVideoCallSupported(boolean rcsIpVideoCallSupported) {
         this.mRcsIpVideoCallSupported = rcsIpVideoCallSupported;
     }
+
+    /**
+     * @deprecated Use {@link #addCapability(String, String)} instead.
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setRcsIpVideoOnlyCallSupported(boolean rcsIpVideoOnlyCallSupported) {
         this.mRcsIpVideoOnlyCallSupported = rcsIpVideoOnlyCallSupported;
@@ -407,6 +552,7 @@
 
     /**
      * Checks whether Geo Push via SMS is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isGeoSmsSupported() {
         return mGeoSmsSupported;
@@ -414,6 +560,7 @@
 
     /**
      * Sets Geolocation Push via SMS as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setGeoSmsSupported(boolean geoSmsSupported) {
          this.mGeoSmsSupported = geoSmsSupported;
@@ -421,6 +568,7 @@
 
     /**
      * Checks whether RCS call composer is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isCallComposerSupported() {
         return mCallComposerSupported;
@@ -428,6 +576,7 @@
 
     /**
      * Sets call composer as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setCallComposerSupported(boolean callComposerSupported) {
         this.mCallComposerSupported = callComposerSupported;
@@ -435,6 +584,7 @@
 
     /**
      * Checks whether post call is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isPostCallSupported(){
         return mPostCallSupported;
@@ -442,13 +592,15 @@
 
     /**
      * Sets post call as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
-     public void setPostCallSupported(boolean postCallSupported) {
-         this.mPostCallSupported = postCallSupported;
-     }
+    public void setPostCallSupported(boolean postCallSupported) {
+        this.mPostCallSupported = postCallSupported;
+    }
 
     /**
      * Checks whether shared map is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isSharedMapSupported() {
         return mSharedMapSupported;
@@ -456,6 +608,7 @@
 
     /**
      * Sets shared map as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setSharedMapSupported(boolean sharedMapSupported) {
         this.mSharedMapSupported = sharedMapSupported;
@@ -463,6 +616,7 @@
 
     /**
      * Checks whether shared sketch is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isSharedSketchSupported() {
         return mSharedSketchSupported;
@@ -470,6 +624,7 @@
 
     /**
      * Sets shared sketch as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setSharedSketchSupported(boolean sharedSketchSupported) {
         this.mSharedSketchSupported = sharedSketchSupported;
@@ -477,6 +632,7 @@
 
     /**
      * Checks whether chatbot communication is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isChatbotSupported() {
         return mChatbotSupported;
@@ -484,6 +640,7 @@
 
     /**
      * Sets chatbot communication as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setChatbotSupported(boolean chatbotSupported) {
         this.mChatbotSupported = chatbotSupported;
@@ -491,6 +648,7 @@
 
     /**
      * Checks whether chatbot role is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isChatbotRoleSupported() {
         return mChatbotRoleSupported;
@@ -498,6 +656,7 @@
 
     /**
      * Sets chatbot role as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setChatbotRoleSupported(boolean chatbotRoleSupported) {
         this.mChatbotRoleSupported = chatbotRoleSupported;
@@ -505,6 +664,7 @@
 
     /**
      * Checks whether standalone chatbot communication is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isSmChatbotSupported() {
         return mSmChatbotSupported;
@@ -512,6 +672,7 @@
 
     /**
      * Sets standalone chatbot communication as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setSmChatbotSupported(boolean smChatbotSupported) {
         this.mSmChatbotSupported = smChatbotSupported;
@@ -519,6 +680,7 @@
 
     /**
      * Checks whether Mmtel based call composer is supported.
+     * @deprecated Use {@link #isCapabilitySupported(String)} instead.
      */
     public boolean isMmtelCallComposerSupported() {
         return mMmtelCallComposerSupported;
@@ -526,6 +688,7 @@
 
     /**
      * Sets Mmtel based call composer as supported or not supported.
+     * @deprecated Use {@link #addCapability(String, String)} instead.
      */
     public void setMmtelCallComposerSupported(boolean mmtelCallComposerSupported) {
         this.mMmtelCallComposerSupported = mmtelCallComposerSupported;
@@ -555,6 +718,84 @@
         this.mCapTimestamp = capTimestamp;
     }
 
+    /**
+     * Adds the feature tag string with supported versions to
+     * the mCapInfoMap.
+     * Map<String featureType, String versions>
+     * Versions format:
+     *    "+g.gsma.rcs.botversion=\"#=1"        -> Version 1 supported
+     *    "+g.gsma.rcs.botversion=\"#=1,#=2\""  -> Versions 1 and 2 are supported
+     *
+     * Example #1: Add standard feature tag with one version support
+     * addCapability(CapInfo.STANDALONE_CHATBOT, "+g.gsma.rcs.botversion=\"#=1");
+     * The above example indicates standalone chatbot feature tag is supported
+     * in version 1.
+     *
+     * Example #2: Add standard feature tag with multiple version support
+     * addCapability(CapInfo.CHATBOT, "+g.gsma.rcs.botversion=\"#=1,#=2\"");
+     * The above example indicates session based chatbot feature tag is supported
+     * in versions 1 and 2.
+     *
+     * Example #3: Add standard feature tag with no version support
+     * addCapability(CapInfo.INSTANT_MSG, "");
+     * The above example indicates im feature tag does not have version support.
+     *
+     * Example #4: Add custom/extension feature tag with no version support
+     * addCapability("+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.custom_im\"",
+     *               "");
+     * Call setNewFeatureTag(int presenceServiceHdl, String featureTag,
+     *           in PresServiceInfo serviceInfo, int userData) API
+     * in IPresenceService.aidl before calling addCapability() API
+     */
+    public void addCapability(String featureTagName, String versions) {
+        this.mCapInfoMap.put(featureTagName, versions);
+    }
+
+    /**
+     * Returns String of versions of the feature tag passed.
+     * Returns "" if versioning support is not present for the feature tag passed.
+     * Returns null if feature tag is not present.
+     *
+     * Example # 1:
+     * getCapabilityVersions(CapInfo.STANDALONE_CHATBOT);
+     * The above returns String in this format "+g.gsma.rcs.botversion=\"#=1,#=2\"",
+     * indicating more than one versions are supported for standalone chatbot feature tag
+     *
+     * Example # 2:
+     * getCapabilityVersions(CapInfo.INSTANT_MSG);
+     * The above returns empty String in this format "",
+     * indicating versions support is not present for im feature tag
+     *
+     * Example #3:
+     * getCapabilityVersions(
+     *   "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.custom_im\");
+     * The above returns String "",
+     * indicating version supported is not present for the custom feature tag passed.
+     */
+    public String getCapabilityVersions(String featureTagName) {
+        return mCapInfoMap.get(featureTagName);
+    }
+
+    /** Removes the entry of the feature tag passed, from the Map. */
+    public void removeCapability(String featureTagName) {
+        this.mCapInfoMap.remove(featureTagName);
+    }
+
+    /** Sets Map of feature tag string and string of supported versions. */
+    public void setCapInfoMap(Map<String, String> capInfoMap) {
+        this.mCapInfoMap = capInfoMap;
+    }
+
+    /** Gets Map of feature tag string and string of supported versions. */
+    public Map<String, String> getCapInfoMap() {
+        return mCapInfoMap;
+    }
+
+    /** Checks whether the featureTag is supported or not. */
+    public boolean isCapabilitySupported(String featureTag) {
+       return mCapInfoMap.containsKey(featureTag);
+    }
+
     public int describeContents() {
         // TODO Auto-generated method stub
         return 0;
@@ -594,6 +835,12 @@
         dest.writeInt(mRcsIpVideoOnlyCallSupported ? 1 : 0);
         dest.writeStringArray(mExts);
         dest.writeLong(mCapTimestamp);
+
+        Bundle capInfoBundle = new Bundle();
+        for (Map.Entry<String, String> entry : mCapInfoMap.entrySet()) {
+          capInfoBundle.putString(entry.getKey(), entry.getValue());
+        }
+        dest.writeBundle(capInfoBundle);
     }
 
     public static final Parcelable.Creator<CapInfo> CREATOR = new Parcelable.Creator<CapInfo>() {
@@ -646,5 +893,10 @@
 
         mExts = source.createStringArray();
         mCapTimestamp = source.readLong();
+
+        Bundle capInfoBundle = source.readBundle();
+        for (String key: capInfoBundle.keySet()) {
+          mCapInfoMap.put(key, capInfoBundle.getString(key));
+        }
     }
 }
diff --git a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
index acea0f0..3242081 100644
--- a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
+++ b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
@@ -30,6 +30,7 @@
     private int mSipResponseCode = 0;
     private int mRetryAfter = 0;
     private String mReasonPhrase = "";
+    private String mReasonHeader = "";
 
     /**
      * Gets the Options command ID.
@@ -117,6 +118,22 @@
     }
 
     /**
+     * Gets the reason header associated with the SIP response code.
+     * @hide
+     */
+    public String getReasonHeader() {
+        return mReasonHeader;
+    }
+
+    /**
+     * Sets the SIP response code reason phrase.
+     * @hide
+     */
+    public void setReasonHeader(String reasonHeader) {
+        this.mReasonHeader = reasonHeader;
+    }
+
+    /**
      * Constructor for the OptionsSipResponse class.
      * @hide
      */
@@ -138,6 +155,7 @@
         dest.writeString(mReasonPhrase);
         dest.writeParcelable(mCmdId, flags);
         dest.writeInt(mRetryAfter);
+        dest.writeString(mReasonHeader);
     }
 
     /** @hide */
@@ -164,5 +182,6 @@
         mReasonPhrase = source.readString();
         mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader());
         mRetryAfter = source.readInt();
+        mReasonHeader = source.readString();
     }
 }
diff --git a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
index 9549152..5e394ef 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
@@ -29,6 +29,7 @@
     private int mSipResponseCode = 0;
     private int mRetryAfter = 0;
     private String mReasonPhrase = "";
+    private String mReasonHeader = "";
 
     /**
      * Gets the Presence command ID.
@@ -123,6 +124,23 @@
     }
 
     /**
+     * Gets the reason header associated with the SIP response
+     * code.
+     * @hide
+     */
+    public String getReasonHeader() {
+        return mReasonHeader;
+    }
+
+    /**
+     * Sets the SIP response code reason header.
+     * @hide
+     */
+    public void setReasonHeader(String reasonHeader) {
+        this.mReasonHeader = reasonHeader;
+    }
+
+    /**
      * Constructor for the PresSipResponse class.
      * @hide
      */
@@ -141,6 +159,7 @@
         dest.writeString(mReasonPhrase);
         dest.writeParcelable(mCmdId, flags);
         dest.writeInt(mRetryAfter);
+        dest.writeString(mReasonHeader);
     }
 
     /** @hide */
@@ -168,5 +187,6 @@
         mReasonPhrase = source.readString();
         mCmdId = source.readParcelable(PresCmdId.class.getClassLoader());
         mRetryAfter = source.readInt();
+        mReasonHeader = source.readString();
     }
 }
\ No newline at end of file
diff --git a/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
index 34a7b1e..ce3d568 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
@@ -27,6 +27,7 @@
     private String mFeatureTag = "";
     private String mContactUri = "";
     private String mTimestamp = "";
+    private String mVersion = "";
 
 
     /**
@@ -80,6 +81,22 @@
     }
 
     /**
+     * Gets the version.
+     * @hide
+     */
+    public String getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Sets the version.
+     * @hide
+     */
+    public void setVersion(String version) {
+        this.mVersion = version;
+    }
+
+    /**
      * Constructor for the PresTupleInfo class.
      * @hide
      */
@@ -96,6 +113,7 @@
         dest.writeString(mFeatureTag);
         dest.writeString(mContactUri);
         dest.writeString(mTimestamp);
+        dest.writeString(mVersion);
     }
 
     /** @hide */
@@ -121,5 +139,6 @@
         mFeatureTag = source.readString();
         mContactUri = source.readString();
         mTimestamp = source.readString();
+        mVersion = source.readString();
     }
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index 179ac8b..a611d65d 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -39,6 +39,9 @@
 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_FULL_SCREEN;
 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_UNKNOWN_MODE;
 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_WINDOW;
+import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_CLICKED;
+import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SERVICE_DISABLED;
+import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SHOWN;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -50,6 +53,16 @@
 
 /** Methods for logging accessibility states. */
 public final class AccessibilityStatsLogUtils {
+    /** The status represents an accessibility privacy warning has been shown. */
+    public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN =
+            NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SHOWN;
+    /** The status represents an accessibility privacy warning has been clicked to review. */
+    public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED =
+            NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_CLICKED;
+    /** The status represents an accessibility privacy warning service has been disabled. */
+    public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED =
+            NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SERVICE_DISABLED;
+
     private static final int UNKNOWN_STATUS =
             ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__UNKNOWN;
 
@@ -154,6 +167,23 @@
                 convertToLoggingMagnificationMode(mode));
     }
 
+    /**
+     * Logs the warning status of the non-a11yTool service. Calls this when the warning status is
+     * changed.
+     *
+     * @param packageName    The package name of the non-a11yTool service
+     * @param status         The warning status of the non-a11yTool service, it should be one of
+     *                       {@code ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN},{@code
+     *                       ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED} and {@code
+     *                       ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED}
+     * @param durationMillis The duration in milliseconds between current and previous status
+     */
+    public static void logNonA11yToolServiceWarningReported(String packageName, int status,
+            long durationMillis) {
+        FrameworkStatsLog.write(FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORT,
+                packageName, status, durationMillis);
+    }
+
     private static boolean isAccessibilityFloatingMenuEnabled(Context context) {
         return Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 786af5f..4d0f4c2 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -45,7 +45,6 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
-import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -71,11 +70,9 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -86,14 +83,10 @@
 import android.provider.OpenableColumns;
 import android.provider.Settings;
 import android.service.chooser.ChooserTarget;
-import android.service.chooser.ChooserTargetService;
-import android.service.chooser.IChooserTargetResult;
-import android.service.chooser.IChooserTargetService;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.HashedStringCache;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Size;
 import android.util.Slog;
 import android.view.LayoutInflater;
@@ -145,10 +138,8 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * The Chooser Activity handles intent resolution specifically for sharing intents -
@@ -206,7 +197,6 @@
     private boolean mIsAppPredictorComponentAvailable;
     private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
     private Map<ChooserTarget, ShortcutInfo> mDirectShareShortcutInfoCache;
-    private Map<ComponentName, ComponentName> mChooserTargetComponentNameCache;
 
     public static final int TARGET_TYPE_DEFAULT = 0;
     public static final int TARGET_TYPE_CHOOSER_TARGET = 1;
@@ -227,8 +217,6 @@
     // statsd logger wrapper
     protected ChooserActivityLogger mChooserActivityLogger;
 
-    private static final boolean USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS = true;
-
     @IntDef(flag = false, prefix = { "TARGET_TYPE_" }, value = {
             TARGET_TYPE_DEFAULT,
             TARGET_TYPE_CHOOSER_TARGET,
@@ -268,7 +256,6 @@
     private long mChooserShownTime;
     protected boolean mIsSuccessfullySelected;
 
-    private long mQueriedTargetServicesTimeMs;
     private long mQueriedSharingShortcutsTimeMs;
 
     private int mChooserRowServiceSpacing;
@@ -278,9 +265,6 @@
 
     private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
 
-    private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
-    private final Set<Pair<ComponentName, UserHandle>> mServicesRequested = new HashSet<>();
-
     private static final int MAX_LOG_RANK_POSITION = 12;
 
     private static final int MAX_EXTRA_INITIAL_INTENTS = 2;
@@ -457,56 +441,16 @@
     private final ChooserHandler mChooserHandler = new ChooserHandler();
 
     private class ChooserHandler extends Handler {
-        private static final int CHOOSER_TARGET_SERVICE_RESULT = 1;
-        private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT = 2;
-        private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT = 3;
         private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 4;
         private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 5;
         private static final int LIST_VIEW_UPDATE_MESSAGE = 6;
 
-        private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 1000;
-        private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 300;
-
-        private boolean mMinTimeoutPassed = false;
-
         private void removeAllMessages() {
             removeMessages(LIST_VIEW_UPDATE_MESSAGE);
-            removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT);
-            removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT);
-            removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
             removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT);
             removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED);
         }
 
-        private void restartServiceRequestTimer() {
-            mMinTimeoutPassed = false;
-            removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT);
-            removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT);
-
-            if (DEBUG) {
-                Log.d(TAG, "queryTargets setting watchdog timer for "
-                        + WATCHDOG_TIMEOUT_MAX_MILLIS + "ms");
-            }
-
-            sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT,
-                    WATCHDOG_TIMEOUT_MIN_MILLIS);
-            sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT,
-                    WATCHDOG_TIMEOUT_MAX_MILLIS);
-        }
-
-        private void maybeStopServiceRequestTimer() {
-            // Set a minimum timeout threshold, to ensure both apis, sharing shortcuts
-            // and older-style direct share services, have had time to load, otherwise
-            // just checking mServiceConnections could force us to end prematurely
-            if (mMinTimeoutPassed && mServiceConnections.isEmpty()) {
-                logDirectShareTargetReceived(
-                        MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
-                sendVoiceChoicesIfNeeded();
-                mChooserMultiProfilePagerAdapter.getActiveListAdapter()
-                        .completeServiceTargetLoading();
-            }
-        }
-
         @Override
         public void handleMessage(Message msg) {
             if (mChooserMultiProfilePagerAdapter.getActiveListAdapter() == null || isDestroyed()) {
@@ -514,51 +458,6 @@
             }
 
             switch (msg.what) {
-                case CHOOSER_TARGET_SERVICE_RESULT:
-                    if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_SERVICE_RESULT");
-                    final ServiceResultInfo sri = (ServiceResultInfo) msg.obj;
-                    if (!mServiceConnections.contains(sri.connection)) {
-                        Log.w(TAG, "ChooserTargetServiceConnection " + sri.connection
-                                + sri.originalTarget.getResolveInfo().activityInfo.packageName
-                                + " returned after being removed from active connections."
-                                + " Have you considered returning results faster?");
-                        break;
-                    }
-                    if (sri.resultTargets != null) {
-                        ChooserListAdapter adapterForUserHandle =
-                                mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle(
-                                        sri.userHandle);
-                        if (adapterForUserHandle != null) {
-                            adapterForUserHandle.addServiceResults(sri.originalTarget,
-                                    sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET,
-                                    /* directShareShortcutInfoCache */ null, mServiceConnections);
-                            if (!sri.resultTargets.isEmpty() && sri.originalTarget != null) {
-                                mChooserTargetComponentNameCache.put(
-                                        sri.resultTargets.get(0).getComponentName(),
-                                        sri.originalTarget.getResolvedComponentName());
-                            }
-                        }
-                    }
-                    unbindService(sri.connection);
-                    sri.connection.destroy();
-                    mServiceConnections.remove(sri.connection);
-                    maybeStopServiceRequestTimer();
-                    break;
-
-                case CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT:
-                    mMinTimeoutPassed = true;
-                    maybeStopServiceRequestTimer();
-                    break;
-
-                case CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT:
-                    mMinTimeoutPassed = true;
-                    if (!mServiceConnections.isEmpty()) {
-                        getChooserActivityLogger().logSharesheetDirectLoadTimeout();
-                    }
-                    unbindRemainingServices();
-                    maybeStopServiceRequestTimer();
-                    break;
-
                 case LIST_VIEW_UPDATE_MESSAGE:
                     if (DEBUG) {
                         Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; ");
@@ -579,7 +478,7 @@
                         if (adapterForUserHandle != null) {
                             adapterForUserHandle.addServiceResults(
                                     resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1,
-                                    mDirectShareShortcutInfoCache, mServiceConnections);
+                                    mDirectShareShortcutInfoCache);
                         }
                     }
                     break;
@@ -589,6 +488,9 @@
                             MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER);
                     sendVoiceChoicesIfNeeded();
                     getChooserActivityLogger().logSharesheetDirectLoadComplete();
+
+                    mChooserMultiProfilePagerAdapter.getActiveListAdapter()
+                            .completeServiceTargetLoading();
                     break;
 
                 default:
@@ -800,7 +702,6 @@
                 target.getAction()
         );
         mDirectShareShortcutInfoCache = new HashMap<>();
-        mChooserTargetComponentNameCache = new HashMap<>();
 
         setEnterSharedElementCallback(new SharedElementCallback() {
             @Override
@@ -1640,7 +1541,6 @@
             mRefinementResultReceiver.destroy();
             mRefinementResultReceiver = null;
         }
-        unbindRemainingServices();
         mChooserHandler.removeAllMessages();
 
         if (mPreviewCoord != null) mPreviewCoord.cancelLoads();
@@ -1697,7 +1597,7 @@
                     /* origTarget */ null,
                     Lists.newArrayList(mCallerChooserTargets),
                     TARGET_TYPE_DEFAULT,
-                    /* directShareShortcutInfoCache */ null, mServiceConnections);
+                    /* directShareShortcutInfoCache */ null);
         }
     }
 
@@ -1935,98 +1835,6 @@
         }
     }
 
-    @VisibleForTesting
-    protected void queryTargetServices(ChooserListAdapter adapter) {
-
-        mQueriedTargetServicesTimeMs = System.currentTimeMillis();
-
-        Context selectedProfileContext = createContextAsUser(
-                adapter.getUserHandle(), 0 /* flags */);
-        final PackageManager pm = selectedProfileContext.getPackageManager();
-        ShortcutManager sm = selectedProfileContext.getSystemService(ShortcutManager.class);
-        int targetsToQuery = 0;
-
-        for (int i = 0, N = adapter.getDisplayResolveInfoCount(); i < N; i++) {
-            final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
-            if (adapter.getScore(dri) == 0) {
-                // A score of 0 means the app hasn't been used in some time;
-                // don't query it as it's not likely to be relevant.
-                continue;
-            }
-            final ActivityInfo ai = dri.getResolveInfo().activityInfo;
-            if (sm.hasShareTargets(ai.packageName)) {
-                // Share targets will be queried from ShortcutManager
-                continue;
-            }
-            final Bundle md = ai.metaData;
-            final String serviceName = md != null ? convertServiceName(ai.packageName,
-                    md.getString(ChooserTargetService.META_DATA_NAME)) : null;
-            if (serviceName != null && ChooserFlags.USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS) {
-                final ComponentName serviceComponent = new ComponentName(
-                        ai.packageName, serviceName);
-
-                UserHandle userHandle = adapter.getUserHandle();
-                Pair<ComponentName, UserHandle> requestedItem =
-                        new Pair<>(serviceComponent, userHandle);
-                if (mServicesRequested.contains(requestedItem)) {
-                    continue;
-                }
-                mServicesRequested.add(requestedItem);
-
-                final Intent serviceIntent = new Intent(ChooserTargetService.SERVICE_INTERFACE)
-                        .setComponent(serviceComponent);
-
-                if (DEBUG) {
-                    Log.d(TAG, "queryTargets found target with service " + serviceComponent);
-                }
-
-                try {
-                    final String perm = pm.getServiceInfo(serviceComponent, 0).permission;
-                    if (!ChooserTargetService.BIND_PERMISSION.equals(perm)) {
-                        Log.w(TAG, "ChooserTargetService " + serviceComponent + " does not require"
-                                + " permission " + ChooserTargetService.BIND_PERMISSION
-                                + " - this service will not be queried for ChooserTargets."
-                                + " add android:permission=\""
-                                + ChooserTargetService.BIND_PERMISSION + "\""
-                                + " to the <service> tag for " + serviceComponent
-                                + " in the manifest.");
-                        continue;
-                    }
-                } catch (NameNotFoundException e) {
-                    Log.e(TAG, "Could not look up service " + serviceComponent
-                            + "; component name not found");
-                    continue;
-                }
-
-                final ChooserTargetServiceConnection conn =
-                        new ChooserTargetServiceConnection(this, dri,
-                                adapter.getUserHandle());
-
-                // Explicitly specify the user handle instead of calling bindService
-                // to avoid the warning from calling from the system process without an explicit
-                // user handle
-                if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND,
-                        adapter.getUserHandle())) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Binding service connection for target " + dri
-                                + " intent " + serviceIntent);
-                    }
-                    mServiceConnections.add(conn);
-                    targetsToQuery++;
-                }
-            }
-            if (targetsToQuery >= QUERY_TARGET_SERVICE_LIMIT) {
-                if (DEBUG) {
-                    Log.d(TAG, "queryTargets hit query target limit "
-                            + QUERY_TARGET_SERVICE_LIMIT);
-                }
-                break;
-            }
-        }
-
-        mChooserHandler.restartServiceRequestTimer();
-    }
-
     private IntentFilter getTargetIntentFilter() {
         try {
             final Intent intent = getTargetIntent();
@@ -2140,7 +1948,6 @@
         // Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path
         // for direct share targets. After ShareSheet is refactored we should use the
         // ShareShortcutInfos directly.
-        boolean resultMessageSent = false;
         for (int i = 0; i < chooserListAdapter.getDisplayResolveInfoCount(); i++) {
             List<ShortcutManager.ShareShortcutInfo> matchingShortcuts = new ArrayList<>();
             for (int j = 0; j < resultList.size(); j++) {
@@ -2155,20 +1962,15 @@
             List<ChooserTarget> chooserTargets = convertToChooserTarget(
                     matchingShortcuts, resultList, appTargets, shortcutType);
 
-
-
             final Message msg = Message.obtain();
             msg.what = ChooserHandler.SHORTCUT_MANAGER_SHARE_TARGET_RESULT;
             msg.obj = new ServiceResultInfo(chooserListAdapter.getDisplayResolveInfo(i),
-                    chooserTargets, null, userHandle);
+                    chooserTargets, userHandle);
             msg.arg1 = shortcutType;
             mChooserHandler.sendMessage(msg);
-            resultMessageSent = true;
         }
 
-        if (resultMessageSent) {
-            sendShortcutManagerShareTargetResultCompleted();
-        }
+        sendShortcutManagerShareTargetResultCompleted();
     }
 
     private void sendShortcutManagerShareTargetResultCompleted() {
@@ -2282,25 +2084,8 @@
         return fullName;
     }
 
-    void unbindRemainingServices() {
-        if (DEBUG) {
-            Log.d(TAG, "unbindRemainingServices, " + mServiceConnections.size() + " left");
-        }
-        for (int i = 0, N = mServiceConnections.size(); i < N; i++) {
-            final ChooserTargetServiceConnection conn = mServiceConnections.get(i);
-            if (DEBUG) Log.d(TAG, "unbinding " + conn);
-            unbindService(conn);
-            conn.destroy();
-        }
-        mServicesRequested.clear();
-        mServiceConnections.clear();
-    }
-
     private void logDirectShareTargetReceived(int logCategory) {
-        final long queryTime =
-                logCategory == MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER
-                        ? mQueriedSharingShortcutsTimeMs : mQueriedTargetServicesTimeMs;
-        final int apiLatency = (int) (System.currentTimeMillis() - queryTime);
+        final int apiLatency = (int) (System.currentTimeMillis() - mQueriedSharingShortcutsTimeMs);
         getMetricsLogger().write(new LogMaker(logCategory).setSubtype(apiLatency));
     }
 
@@ -2346,8 +2131,7 @@
         List<AppTargetId> targetIds = new ArrayList<>();
         for (ChooserTargetInfo chooserTargetInfo : surfacedTargetInfo) {
             ChooserTarget chooserTarget = chooserTargetInfo.getChooserTarget();
-            ComponentName componentName = mChooserTargetComponentNameCache.getOrDefault(
-                    chooserTarget.getComponentName(), chooserTarget.getComponentName());
+            ComponentName componentName = chooserTarget.getComponentName();
             if (mDirectShareShortcutInfoCache.containsKey(chooserTarget)) {
                 String shortcutId = mDirectShareShortcutInfoCache.get(chooserTarget).getId();
                 targetIds.add(new AppTargetId(
@@ -2838,7 +2622,6 @@
 
     @Override // ResolverListCommunicator
     public void onHandlePackagesChanged(ResolverListAdapter listAdapter) {
-        mServicesRequested.clear();
         mChooserMultiProfilePagerAdapter.getActiveListAdapter().notifyDataSetChanged();
         super.onHandlePackagesChanged(listAdapter);
     }
@@ -2906,13 +2689,6 @@
 
             queryDirectShareTargets(chooserListAdapter, false);
         }
-        if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
-            if (DEBUG) {
-                Log.d(TAG, "List built querying services");
-            }
-
-            queryTargetServices(chooserListAdapter);
-        }
 
         getChooserActivityLogger().logSharesheetAppLoadComplete();
     }
@@ -3953,116 +3729,15 @@
         }
     }
 
-    static class ChooserTargetServiceConnection implements ServiceConnection {
-        private DisplayResolveInfo mOriginalTarget;
-        private ComponentName mConnectedComponent;
-        private ChooserActivity mChooserActivity;
-        private final UserHandle mUserHandle;
-        private final Object mLock = new Object();
-
-        private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
-            @Override
-            public void sendResult(List<ChooserTarget> targets) throws RemoteException {
-                synchronized (mLock) {
-                    if (mChooserActivity == null) {
-                        Log.e(TAG, "destroyed ChooserTargetServiceConnection received result from "
-                                + mConnectedComponent + "; ignoring...");
-                        return;
-                    }
-                    Context contextAsUser =
-                            mChooserActivity.createContextAsUser(mUserHandle, 0 /* flags */);
-                    mChooserActivity.filterServiceTargets(contextAsUser,
-                            mOriginalTarget.getResolveInfo().activityInfo.packageName, targets);
-                    final Message msg = Message.obtain();
-                    msg.what = ChooserHandler.CHOOSER_TARGET_SERVICE_RESULT;
-                    msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
-                            ChooserTargetServiceConnection.this, mUserHandle);
-                    mChooserActivity.mChooserHandler.sendMessage(msg);
-                }
-            }
-        };
-
-        public ChooserTargetServiceConnection(ChooserActivity chooserActivity,
-                DisplayResolveInfo dri, UserHandle userHandle) {
-            mChooserActivity = chooserActivity;
-            mOriginalTarget = dri;
-            mUserHandle = userHandle;
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Log.d(TAG, "onServiceConnected: " + name);
-            synchronized (mLock) {
-                if (mChooserActivity == null) {
-                    Log.e(TAG, "destroyed ChooserTargetServiceConnection got onServiceConnected");
-                    return;
-                }
-
-                final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
-                try {
-                    icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
-                            mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
-                    mChooserActivity.unbindService(this);
-                    mChooserActivity.mServiceConnections.remove(this);
-                    destroy();
-                }
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
-            synchronized (mLock) {
-                if (mChooserActivity == null) {
-                    Log.e(TAG,
-                            "destroyed ChooserTargetServiceConnection got onServiceDisconnected");
-                    return;
-                }
-
-                mChooserActivity.unbindService(this);
-                mChooserActivity.mServiceConnections.remove(this);
-                if (mChooserActivity.mServiceConnections.isEmpty()) {
-                    mChooserActivity.sendVoiceChoicesIfNeeded();
-                }
-                mConnectedComponent = null;
-                destroy();
-            }
-        }
-
-        public void destroy() {
-            synchronized (mLock) {
-                mChooserActivity = null;
-                mOriginalTarget = null;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "ChooserTargetServiceConnection{service="
-                    + mConnectedComponent + ", activity="
-                    + (mOriginalTarget != null
-                    ? mOriginalTarget.getResolveInfo().activityInfo.toString()
-                    : "<connection destroyed>") + "}";
-        }
-
-        public ComponentName getComponentName() {
-            return mOriginalTarget.getResolveInfo().activityInfo.getComponentName();
-        }
-    }
-
     static class ServiceResultInfo {
         public final DisplayResolveInfo originalTarget;
         public final List<ChooserTarget> resultTargets;
-        public final ChooserTargetServiceConnection connection;
         public final UserHandle userHandle;
 
         public ServiceResultInfo(DisplayResolveInfo ot, List<ChooserTarget> rt,
-                ChooserTargetServiceConnection c, UserHandle userHandle) {
+                UserHandle userHandle) {
             originalTarget = ot;
             resultTargets = rt;
-            connection = c;
             this.userHandle = userHandle;
         }
     }
diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java
index 1a93f1b..ab6b0f8 100644
--- a/core/java/com/android/internal/app/ChooserFlags.java
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -17,9 +17,6 @@
 package com.android.internal.app;
 
 import android.app.prediction.AppPredictionManager;
-import android.provider.DeviceConfig;
-
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 
 /**
  * Common flags for {@link ChooserListAdapter} and {@link ChooserActivity}.
@@ -27,15 +24,6 @@
 public class ChooserFlags {
 
     /**
-     * Whether to use the deprecated {@link android.service.chooser.ChooserTargetService} API for
-     * direct share targets. If true, both CTS and Shortcuts will be used to find Direct Share
-     * targets. If false, only Shortcuts will be used.
-     */
-    public static final boolean USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS =
-            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, false);
-
-    /**
      * Whether to use {@link AppPredictionManager} to query for direct share targets (as opposed to
      * talking directly to {@link android.content.pm.ShortcutManager}.
      */
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 87737ca..07c4050 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -491,9 +491,7 @@
      */
     public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
             @ChooserActivity.ShareTargetType int targetType,
-            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos,
-            List<ChooserActivity.ChooserTargetServiceConnection>
-                    pendingChooserTargetServiceConnections) {
+            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos) {
         if (DEBUG) {
             Log.d(TAG, "addServiceResults " + origTarget.getResolvedComponentName() + ", "
                     + targets.size()
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index c16ee42..7d2cb50 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -789,6 +789,9 @@
             } else {
                 mDisplayResolveInfo.setDisplayIcon(d);
                 mHolder.bindIcon(mDisplayResolveInfo);
+                // Notify in case view is already bound to resolve the race conditions on
+                // low end devices
+                notifyDataSetChanged();
             }
         }
 
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 84354d9..ec224e5 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -72,17 +72,19 @@
     private Resources mSuspendingAppResources;
     private SuspendDialogInfo mSuppliedDialogInfo;
     private Bundle mOptions;
-    private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mSuspendModifiedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) {
-                final String[] unsuspended = intent.getStringArrayExtra(
+            if (Intent.ACTION_PACKAGES_SUSPENSION_CHANGED.equals(intent.getAction())) {
+                // Suspension conditions were modified, dismiss any related visible dialogs.
+                final String[] modified = intent.getStringArrayExtra(
                         Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) {
+                if (ArrayUtils.contains(modified, mSuspendedPackage)) {
                     if (!isFinishing()) {
-                        Slog.w(TAG, "Package " + mSuspendedPackage
-                                + " got unsuspended while the dialog was visible. Finishing.");
+                        Slog.w(TAG, "Package " + mSuspendedPackage + " has modified"
+                                + " suspension conditions while dialog was visible. Finishing.");
                         SuspendedAppActivity.this.finish();
+                        // TODO (b/198201994): reload the suspend dialog to show most relevant info
                     }
                 }
             }
@@ -245,15 +247,16 @@
 
         setupAlert();
 
-        final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED);
-        registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null,
-                null);
+        final IntentFilter suspendModifiedFilter =
+                new IntentFilter(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED);
+        registerReceiverAsUser(mSuspendModifiedReceiver, UserHandle.of(mUserId),
+                suspendModifiedFilter, null, null);
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        unregisterReceiver(mUnsuspendReceiver);
+        unregisterReceiver(mSuspendModifiedReceiver);
     }
 
     private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {
diff --git a/core/java/com/android/internal/app/TEST_MAPPING b/core/java/com/android/internal/app/TEST_MAPPING
index 8bd7912..08e1d57 100644
--- a/core/java/com/android/internal/app/TEST_MAPPING
+++ b/core/java/com/android/internal/app/TEST_MAPPING
@@ -3,17 +3,14 @@
     {
       "name": "CtsSuspendAppsTestCases",
       "file_patterns": ["(/|^)SuspendedAppActivity\\.java"]
-    }
-  ],
-  "postsubmit": [
+    },
     {
       "name": "FrameworksCoreTests",
       "options": [
         {
         "include-filter": "com.android.internal.app."
         },
-
-        // Many tests failing - do not enable for continuous execution 
+        // Exclude currently failing tests from presubmit
         {
         "exclude-filter": "com.android.internal.app.IntentForwarderActivityTest"
         },
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 10750b6..0c56c67 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -64,8 +64,7 @@
     public static final String LIB_DIR_NAME = "lib";
     public static final String LIB64_DIR_NAME = "lib64";
 
-    // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
-    // that the cpuAbiOverride must be clear.
+    // Special value for indicating that the cpuAbiOverride must be clear.
     public static final String CLEAR_ABI_OVERRIDE = "-";
 
     /**
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
deleted file mode 100644
index aca761d..0000000
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ /dev/null
@@ -1,140 +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.internal.inputmethod;
-
-import android.annotation.NonNull;
-import android.os.RemoteException;
-
-import java.util.function.BooleanSupplier;
-import java.util.function.IntSupplier;
-import java.util.function.Supplier;
-
-/**
- * Defines a set of helper methods to callback corresponding results in {@link ResultCallbacks}.
- */
-public final class CallbackUtils {
-
-    /**
-     * Not intended to be instantiated.
-     */
-    private CallbackUtils() {
-    }
-
-    /**
-     * A utility method using given {@link IBooleanResultCallback} to callback the result.
-     *
-     * @param callback {@link IBooleanResultCallback} to be called back.
-     * @param resultSupplier the supplier from which the result is provided.
-     */
-    public static void onResult(@NonNull IBooleanResultCallback callback,
-            @NonNull BooleanSupplier resultSupplier) {
-        boolean result = false;
-        Throwable exception = null;
-
-        try {
-            result = resultSupplier.getAsBoolean();
-        } catch (Throwable throwable) {
-            exception = throwable;
-        }
-
-        try {
-            if (exception != null) {
-                callback.onError(ThrowableHolder.of(exception));
-                return;
-            }
-            callback.onResult(result);
-        } catch (RemoteException ignored) { }
-    }
-
-    /**
-     * A utility method using given {@link IIntResultCallback} to callback the result.
-     *
-     * @param callback {@link IIntResultCallback} to be called back.
-     * @param resultSupplier the supplier from which the result is provided.
-     */
-    public static void onResult(@NonNull IIntResultCallback callback,
-            @NonNull IntSupplier resultSupplier) {
-        int result = 0;
-        Throwable exception = null;
-
-        try {
-            result = resultSupplier.getAsInt();
-        } catch (Throwable throwable) {
-            exception = throwable;
-        }
-
-        try {
-            if (exception != null) {
-                callback.onError(ThrowableHolder.of(exception));
-                return;
-            }
-            callback.onResult(result);
-        } catch (RemoteException ignored) { }
-    }
-
-    /**
-     * A utility method using given {@link IVoidResultCallback} to callback the result.
-     *
-     * @param callback {@link IVoidResultCallback} to be called back.
-     * @param runnable to execute the given method
-     */
-    public static void onResult(@NonNull IVoidResultCallback callback,
-            @NonNull Runnable runnable) {
-        Throwable exception = null;
-
-        try {
-            runnable.run();
-        } catch (Throwable throwable) {
-            exception = throwable;
-        }
-
-        try {
-            if (exception != null) {
-                callback.onError(ThrowableHolder.of(exception));
-                return;
-            }
-            callback.onResult();
-        } catch (RemoteException ignored) { }
-    }
-
-    /**
-     * A utility method using given {@link IInputContentUriTokenResultCallback} to callback the
-     * result.
-     *
-     * @param callback {@link IInputContentUriTokenResultCallback} to be called back.
-     * @param resultSupplier the supplier from which the result is provided.
-     */
-    public static void onResult(@NonNull IInputContentUriTokenResultCallback callback,
-            @NonNull Supplier<IInputContentUriToken> resultSupplier) {
-        IInputContentUriToken result = null;
-        Throwable exception = null;
-
-        try {
-            result = resultSupplier.get();
-        } catch (Throwable throwable) {
-            exception = throwable;
-        }
-
-        try {
-            if (exception != null) {
-                callback.onError(ThrowableHolder.of(exception));
-                return;
-            }
-            callback.onResult(result);
-        } catch (RemoteException ignored) { }
-    }
-}
diff --git a/core/java/com/android/internal/inputmethod/CancellationGroup.java b/core/java/com/android/internal/inputmethod/CancellationGroup.java
index aef9e3b..3b2e1cd 100644
--- a/core/java/com/android/internal/inputmethod/CancellationGroup.java
+++ b/core/java/com/android/internal/inputmethod/CancellationGroup.java
@@ -23,49 +23,66 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * A utility class, which works as both a factory class of a cancellation signal to cancel
  * all the completable objects.
+ *
+ * <p>TODO: Make this lock-free.</p>
  */
 public final class CancellationGroup {
     private final Object mLock = new Object();
 
     /**
-     * List of {@link CountDownLatch}, which can be used to propagate {@link #cancelAll()} to
+     * List of {@link CompletableFuture}, which can be used to propagate {@link #cancelAll()} to
      * completable objects.
      *
      * <p>This will be lazily instantiated to avoid unnecessary object allocations.</p>
      */
     @Nullable
     @GuardedBy("mLock")
-    private ArrayList<CountDownLatch> mLatchList = null;
+    private ArrayList<CompletableFuture<?>> mFutureList = null;
 
     @GuardedBy("mLock")
     private boolean mCanceled = false;
 
+    /**
+     * Tries to register the given {@link CompletableFuture} into the callback list if this
+     * {@link CancellationGroup} is not yet cancelled.
+     *
+     * <p>If this {@link CancellationGroup} is already cancelled, then this method will immediately
+     * call {@link CompletableFuture#cancel(boolean)} then return {@code false}.</p>
+     *
+     * <p>When this method returns {@code true}, call {@link #unregisterFuture(CompletableFuture)}
+     * to remove the unnecessary object reference.</p>
+     *
+     * @param future {@link CompletableFuture} to be added to the cancellation callback list.
+     * @return {@code true} if the given {@code future} is added to the callback list.
+     *         {@code false} otherwise.
+     */
     @AnyThread
-    boolean registerLatch(@NonNull CountDownLatch latch) {
+    boolean tryRegisterFutureOrCancelImmediately(@NonNull CompletableFuture<?> future) {
         synchronized (mLock) {
             if (mCanceled) {
+                future.cancel(false);
                 return false;
             }
-            if (mLatchList == null) {
+            if (mFutureList == null) {
                 // Set the initial capacity to 1 with an assumption that usually there is up to 1
                 // on-going operation.
-                mLatchList = new ArrayList<>(1);
+                mFutureList = new ArrayList<>(1);
             }
-            mLatchList.add(latch);
+            mFutureList.add(future);
             return true;
         }
     }
 
     @AnyThread
-    void unregisterLatch(@NonNull CountDownLatch latch) {
+    void unregisterFuture(@NonNull CompletableFuture<?> future) {
         synchronized (mLock) {
-            if (mLatchList != null) {
-                mLatchList.remove(latch);
+            if (mFutureList != null) {
+                mFutureList.remove(future);
             }
         }
     }
@@ -80,10 +97,10 @@
         synchronized (mLock) {
             if (!mCanceled) {
                 mCanceled = true;
-                if (mLatchList != null) {
-                    mLatchList.forEach(CountDownLatch::countDown);
-                    mLatchList.clear();
-                    mLatchList = null;
+                if (mFutureList != null) {
+                    mFutureList.forEach(future -> future.cancel(false));
+                    mFutureList.clear();
+                    mFutureList = null;
                 }
             }
         }
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
deleted file mode 100644
index 132272c..0000000
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ /dev/null
@@ -1,558 +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.internal.inputmethod;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.AnyThread;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.annotation.Retention;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An class to consolidate completable object types supported by
- * {@link CancellationGroup}.
- */
-public final class Completable {
-
-    /**
-     * Not intended to be instantiated.
-     */
-    private Completable() {
-    }
-
-    /**
-     * Base class of all the completable types supported by {@link CancellationGroup}.
-     */
-    protected static class ValueBase {
-        /**
-         * {@link CountDownLatch} to be signaled to unblock
-         * {@link #await(int, TimeUnit, CancellationGroup)}.
-         */
-        private final CountDownLatch mLatch = new CountDownLatch(1);
-
-        /**
-         * Lock {@link Object} to guard complete operations within this class.
-         */
-        protected final Object mStateLock = new Object();
-
-        /**
-         * Indicates the completion state of this object.
-         */
-        @GuardedBy("mStateLock")
-        @CompletionState
-        protected int mState = CompletionState.NOT_COMPLETED;
-
-        /**
-         * {@link Throwable} message passed to {@link #onError(ThrowableHolder)}.
-         *
-         * <p>This is not {@code null} only when {@link #mState} is
-         * {@link CompletionState#COMPLETED_WITH_ERROR}.</p>
-         */
-        @GuardedBy("mStateLock")
-        @Nullable
-        protected String mMessage = null;
-
-        @Retention(SOURCE)
-        @IntDef({
-                CompletionState.NOT_COMPLETED,
-                CompletionState.COMPLETED_WITH_VALUE,
-                CompletionState.COMPLETED_WITH_ERROR})
-        protected @interface CompletionState {
-            /**
-             * This object is not completed yet.
-             */
-            int NOT_COMPLETED = 0;
-            /**
-             * This object is already completed with a value.
-             */
-            int COMPLETED_WITH_VALUE = 1;
-            /**
-             * This object is already completed with an error.
-             */
-            int COMPLETED_WITH_ERROR = 2;
-        }
-
-        /**
-         * Converts the given {@link CompletionState} into a human-readable string.
-         *
-         * @param state {@link CompletionState} to be converted.
-         * @return a human-readable {@link String} for the given {@code state}.
-         */
-        @AnyThread
-        protected static String stateToString(@CompletionState int state) {
-            switch (state) {
-                case CompletionState.NOT_COMPLETED:
-                    return "NOT_COMPLETED";
-                case CompletionState.COMPLETED_WITH_VALUE:
-                    return "COMPLETED_WITH_VALUE";
-                case CompletionState.COMPLETED_WITH_ERROR:
-                    return "COMPLETED_WITH_ERROR";
-                default:
-                    return "Unknown(value=" + state + ")";
-            }
-        }
-
-        /**
-         * @return {@code true} if {@link #onComplete()} gets called and {@link #mState} is
-         *         {@link CompletionState#COMPLETED_WITH_VALUE}.
-         */
-        @AnyThread
-        public boolean hasValue() {
-            synchronized (mStateLock) {
-                return mState == CompletionState.COMPLETED_WITH_VALUE;
-            }
-        }
-
-        /**
-         * Provides the base implementation of {@code getValue()} for derived classes.
-         *
-         * <p>Must be called after acquiring {@link #mStateLock}.</p>
-         *
-         * @throws RuntimeException when {@link #mState} is
-         *                          {@link CompletionState#COMPLETED_WITH_ERROR}.
-         * @throws UnsupportedOperationException when {@link #mState} is not
-         *                                       {@link CompletionState#COMPLETED_WITH_VALUE} and
-         *                                       {@link CompletionState#COMPLETED_WITH_ERROR}.
-         */
-        @GuardedBy("mStateLock")
-        protected void enforceGetValueLocked() {
-            switch (mState) {
-                case CompletionState.NOT_COMPLETED:
-                    throw new UnsupportedOperationException(
-                            "getValue() is allowed only if hasValue() returns true");
-                case CompletionState.COMPLETED_WITH_VALUE:
-                    return;
-                case CompletionState.COMPLETED_WITH_ERROR:
-                    throw new RuntimeException(mMessage);
-                default:
-                    throw new UnsupportedOperationException(
-                            "getValue() is not allowed on state=" + stateToString(mState));
-            }
-        }
-
-        /**
-         * Called by subclasses to signale {@link #mLatch}.
-         */
-        @AnyThread
-        protected void onComplete() {
-            mLatch.countDown();
-        }
-
-        /**
-         * Notify when exception happened.
-         *
-         * @param throwableHolder contains the {@link Throwable} object when exception happened.
-         */
-        @AnyThread
-        protected void onError(ThrowableHolder throwableHolder) {
-            synchronized (mStateLock) {
-                switch (mState) {
-                    case CompletionState.NOT_COMPLETED:
-                        mMessage = throwableHolder.getMessage();
-                        mState = CompletionState.COMPLETED_WITH_ERROR;
-                        break;
-                    default:
-                        throw new UnsupportedOperationException(
-                                "onError() is not allowed on state=" + stateToString(mState));
-                }
-            }
-            onComplete();
-        }
-
-        /**
-         * Blocks the calling thread until at least one of the following conditions is met.
-         *
-         * <p>
-         *     <ol>
-         *         <li>This object becomes ready to return the value.</li>
-         *         <li>{@link CancellationGroup#cancelAll()} gets called.</li>
-         *         <li>The given timeout period has passed.</li>
-         *     </ol>
-         * </p>
-         *
-         * <p>The caller can distinguish the case 1 and case 2 by calling {@link #hasValue()}.
-         * Note that the return value of {@link #hasValue()} can change from {@code false} to
-         * {@code true} at any time, even after this methods finishes with returning
-         * {@code true}.</p>
-         *
-         * @param timeout length of the timeout.
-         * @param timeUnit unit of {@code timeout}.
-         * @param cancellationGroup {@link CancellationGroup} to cancel completable objects.
-         * @return {@code false} if and only if the given timeout period has passed. Otherwise
-         *         {@code true}.
-         */
-        @AnyThread
-        public boolean await(int timeout, @NonNull TimeUnit timeUnit,
-                @Nullable CancellationGroup cancellationGroup) {
-            if (cancellationGroup == null) {
-                return awaitInner(timeout, timeUnit);
-            }
-
-            if (!cancellationGroup.registerLatch(mLatch)) {
-                // Already canceled when this method gets called.
-                return false;
-            }
-            try {
-                return awaitInner(timeout, timeUnit);
-            } finally {
-                cancellationGroup.unregisterLatch(mLatch);
-            }
-        }
-
-        private boolean awaitInner(int timeout, @NonNull TimeUnit timeUnit) {
-            try {
-                return mLatch.await(timeout, timeUnit);
-            } catch (InterruptedException e) {
-                return true;
-            }
-        }
-
-        /**
-         * Blocks the calling thread until this object becomes ready to return the value, even if
-         * {@link InterruptedException} is thrown.
-         */
-        @AnyThread
-        public void await() {
-            boolean interrupted = false;
-            while (true) {
-                try {
-                    mLatch.await();
-                    break;
-                } catch (InterruptedException ignored) {
-                    interrupted = true;
-                }
-            }
-
-            if (interrupted) {
-                // Try to preserve the interrupt bit on this thread.
-                Thread.currentThread().interrupt();
-            }
-        }
-    }
-
-    /**
-     * Completable object of integer primitive.
-     */
-    public static final class Int extends ValueBase {
-        @GuardedBy("mStateLock")
-        private int mValue = 0;
-
-        /**
-         * Notify when a value is set to this completable object.
-         *
-         * @param value value to be set.
-         */
-        @AnyThread
-        void onComplete(int value) {
-            synchronized (mStateLock) {
-                switch (mState) {
-                    case CompletionState.NOT_COMPLETED:
-                        mValue = value;
-                        mState = CompletionState.COMPLETED_WITH_VALUE;
-                        break;
-                    default:
-                        throw new UnsupportedOperationException(
-                                "onComplete() is not allowed on state=" + stateToString(mState));
-                }
-            }
-            onComplete();
-        }
-
-        /**
-         * @return value associated with this object.
-         * @throws RuntimeException when called while {@link #onError} happened.
-         * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
-         *                                       {@code false}.
-         */
-        @AnyThread
-        public int getValue() {
-            synchronized (mStateLock) {
-                enforceGetValueLocked();
-                return mValue;
-            }
-        }
-    }
-
-    /**
-     * Completable object of {@link java.lang.Void}.
-     */
-    public static final class Void extends ValueBase {
-        /**
-         * Notify when this completable object callback.
-         */
-        @AnyThread
-        @Override
-        protected void onComplete() {
-            synchronized (mStateLock) {
-                switch (mState) {
-                    case CompletionState.NOT_COMPLETED:
-                        mState = CompletionState.COMPLETED_WITH_VALUE;
-                        break;
-                    default:
-                        throw new UnsupportedOperationException(
-                                "onComplete() is not allowed on state=" + stateToString(mState));
-                }
-            }
-            super.onComplete();
-        }
-
-        /**
-         * @throws RuntimeException when called while {@link #onError} happened.
-         * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
-         *                                       {@code false}.
-         */
-        @AnyThread
-        public void getValue() {
-            synchronized (mStateLock) {
-                enforceGetValueLocked();
-            }
-        }
-    }
-
-    /**
-     * Base class of completable object types.
-     *
-     * @param <T> type associated with this completable object.
-     */
-    public static class Values<T> extends ValueBase {
-        @GuardedBy("mStateLock")
-        @Nullable
-        private T mValue = null;
-
-        /**
-         * Notify when a value is set to this completable value object.
-         *
-         * @param value value to be set.
-         */
-        @AnyThread
-        void onComplete(@Nullable T value) {
-            synchronized (mStateLock) {
-                switch (mState) {
-                    case CompletionState.NOT_COMPLETED:
-                        mValue = value;
-                        mState = CompletionState.COMPLETED_WITH_VALUE;
-                        break;
-                    default:
-                        throw new UnsupportedOperationException(
-                                "onComplete() is not allowed on state=" + stateToString(mState));
-                }
-            }
-            onComplete();
-        }
-
-        /**
-         * @return value associated with this object.
-         * @throws RuntimeException when called while {@link #onError} happened
-         * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
-         *                                       {@code false}.
-         */
-        @AnyThread
-        @Nullable
-        public T getValue() {
-            synchronized (mStateLock) {
-                enforceGetValueLocked();
-                return mValue;
-            }
-        }
-    }
-
-    /**
-     * @return an instance of {@link Completable.Int}.
-     */
-    public static Completable.Int createInt() {
-        return new Completable.Int();
-    }
-
-    /**
-     * @return an instance of {@link Completable.Boolean}.
-     */
-    public static Completable.Boolean createBoolean() {
-        return new Completable.Boolean();
-    }
-
-    /**
-     * @return an instance of {@link Completable.CharSequence}.
-     */
-    public static Completable.CharSequence createCharSequence() {
-        return new Completable.CharSequence();
-    }
-
-    /**
-     * @return an instance of {@link Completable.ExtractedText}.
-     */
-    public static Completable.ExtractedText createExtractedText() {
-        return new Completable.ExtractedText();
-    }
-
-    /**
-     * @return an instance of {@link Completable.SurroundingText}.
-     */
-    public static Completable.SurroundingText createSurroundingText() {
-        return new Completable.SurroundingText();
-    }
-
-    /**
-     * @return an instance of {@link Completable.IInputContentUriToken}.
-     */
-    public static Completable.IInputContentUriToken createIInputContentUriToken() {
-        return new Completable.IInputContentUriToken();
-    }
-
-    /**
-     * @return an instance of {@link Completable.Void}.
-     */
-    public static Completable.Void createVoid() {
-        return new Completable.Void();
-    }
-
-    /**
-     * Completable object of {@link java.lang.Boolean}.
-     */
-    public static final class Boolean extends Values<java.lang.Boolean> { }
-
-    /**
-     * Completable object of {@link java.lang.CharSequence}.
-     */
-    public static final class CharSequence extends Values<java.lang.CharSequence> { }
-
-    /**
-     * Completable object of {@link android.view.inputmethod.ExtractedText}.
-     */
-    public static final class ExtractedText
-            extends Values<android.view.inputmethod.ExtractedText> { }
-
-    /**
-     * Completable object of {@link android.view.inputmethod.SurroundingText}.
-     */
-    public static final class SurroundingText
-            extends Values<android.view.inputmethod.SurroundingText> { }
-
-    /**
-     * Completable object of {@link IInputContentUriToken>}.
-     */
-    public static final class IInputContentUriToken
-            extends Values<com.android.internal.inputmethod.IInputContentUriToken> { }
-
-    /**
-     * Await the result by the {@link Completable.Values}.
-     *
-     * @return the result once {@link ValueBase#onComplete()}.
-     */
-    @AnyThread
-    @Nullable
-    public static <T> T getResult(@NonNull Completable.Values<T> value) {
-        value.await();
-        return value.getValue();
-    }
-
-    /**
-     * Await the int result by the {@link Completable.Int}.
-     *
-     * @return the result once {@link ValueBase#onComplete()}.
-     */
-    @AnyThread
-    public static int getIntResult(@NonNull Completable.Int value) {
-        value.await();
-        return value.getValue();
-    }
-
-    /**
-     * Await the result by the {@link Completable.Void}.
-     *
-     * Check the result once {@link ValueBase#onComplete()}
-     */
-    @AnyThread
-    public static void getResult(@NonNull Completable.Void value) {
-        value.await();
-        value.getValue();
-    }
-
-    /**
-     * Await the result by the {@link Completable.Boolean}, and log it if there is no result after
-     * given timeout.
-     *
-     * @return the result once {@link ValueBase#onComplete()}
-     */
-    @AnyThread
-    public static boolean getResultOrFalse(@NonNull Completable.Boolean value, String tag,
-            @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
-            int maxWaitTime) {
-        final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
-        if (value.hasValue()) {
-            return value.getValue();
-        }
-        logInternal(tag, methodName, timedOut, maxWaitTime, 0);
-        return false;
-    }
-
-    /**
-     * Await the result by the {@link Completable.Int}, and log it if there is no result after
-     * given timeout.
-     *
-     * @return the result once {@link ValueBase#onComplete()}
-     */
-    @AnyThread
-    public static int getResultOrZero(@NonNull Completable.Int value, String tag,
-            @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
-            int maxWaitTime) {
-        final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
-        if (value.hasValue()) {
-            return value.getValue();
-        }
-        logInternal(tag, methodName, timedOut, maxWaitTime, 0);
-        return 0;
-    }
-
-    /**
-     * Await the result by the {@link Completable.Values}, and log it if there is no result after
-     * given timeout.
-     *
-     * @return the result once {@link ValueBase#onComplete()}
-     */
-    @AnyThread
-    @Nullable
-    public static <T> T getResultOrNull(@NonNull Completable.Values<T> value, String tag,
-            @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
-            int maxWaitTime) {
-        final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
-        if (value.hasValue()) {
-            return value.getValue();
-        }
-        logInternal(tag, methodName, timedOut, maxWaitTime, null);
-        return null;
-    }
-
-    @AnyThread
-    private static void logInternal(String tag, @Nullable String methodName, boolean timedOut,
-            int maxWaitTime, @Nullable Object defaultValue) {
-        if (timedOut) {
-            Log.w(tag, methodName + " didn't respond in " + maxWaitTime + " msec."
-                    + " Returning default: " + defaultValue);
-        } else {
-            Log.w(tag, methodName + " was canceled before complete. Returning default: "
-                    + defaultValue);
-        }
-    }
-}
diff --git a/core/java/com/android/internal/inputmethod/CompletableFutureUtil.java b/core/java/com/android/internal/inputmethod/CompletableFutureUtil.java
new file mode 100644
index 0000000..ec10e01
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/CompletableFutureUtil.java
@@ -0,0 +1,253 @@
+/*
+ * 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 android.annotation.AnyThread;
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A set of helper methods to retrieve result values from {@link CompletableFuture}.
+ */
+public final class CompletableFutureUtil {
+    /**
+     * Not intended to be instantiated.
+     */
+    private CompletableFutureUtil() {
+    }
+
+    @AnyThread
+    @Nullable
+    private static <T> T getValueOrRethrowErrorInternal(@NonNull CompletableFuture<T> future) {
+        boolean interrupted = false;
+        try {
+            while (true) {
+                try {
+                    return future.get();
+                } catch (ExecutionException e) {
+                    final Throwable cause = e.getCause();
+                    throw new RuntimeException(cause.getMessage(), cause.getCause());
+                } catch (InterruptedException e) {
+                    interrupted = true;
+                }
+            }
+        } finally {
+            if (interrupted) {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    @AnyThread
+    @Nullable
+    private static <T> T getValueOrNullInternal(@NonNull CompletableFuture<T> future,
+            @Nullable String tag, @Nullable String methodName,
+            @DurationMillisLong long timeoutMillis, @Nullable CancellationGroup cancellationGroup) {
+        // We intentionally do not use CompletableFuture.anyOf() to avoid additional object
+        // allocations.
+        final boolean needsToUnregister = cancellationGroup != null
+                && cancellationGroup.tryRegisterFutureOrCancelImmediately(future);
+        boolean interrupted = false;
+        try {
+            while (true) {
+                try {
+                    return future.get(timeoutMillis, TimeUnit.MILLISECONDS);
+                } catch (CompletionException e) {
+                    if (e.getCause() instanceof CancellationException) {
+                        logCancellationInternal(tag, methodName);
+                        return null;
+                    }
+                    logErrorInternal(tag, methodName, e.getMessage());
+                    return null;
+                } catch (CancellationException e) {
+                    logCancellationInternal(tag, methodName);
+                    return null;
+                } catch (InterruptedException e) {
+                    interrupted = true;
+                } catch (TimeoutException e) {
+                    logTimeoutInternal(tag, methodName, timeoutMillis);
+                    return null;
+                } catch (Throwable e) {
+                    logErrorInternal(tag, methodName, e.getMessage());
+                    return null;
+                }
+            }
+        } finally {
+            if (needsToUnregister) {
+                cancellationGroup.unregisterFuture(future);
+            }
+            if (interrupted) {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    @AnyThread
+    private static void logTimeoutInternal(@Nullable String tag, @Nullable String methodName,
+            @DurationMillisLong long timeout) {
+        if (tag == null || methodName == null) {
+            return;
+        }
+        Log.w(tag, methodName + " didn't respond in " + timeout + " msec.");
+    }
+
+    @AnyThread
+    private static void logErrorInternal(@Nullable String tag, @Nullable String methodName,
+            @Nullable String errorString) {
+        if (tag == null || methodName == null) {
+            return;
+        }
+        Log.w(tag, methodName + " was failed with an exception=" + errorString);
+    }
+
+    @AnyThread
+    private static void logCancellationInternal(@Nullable String tag, @Nullable String methodName) {
+        if (tag == null || methodName == null) {
+            return;
+        }
+        Log.w(tag, methodName + " was cancelled.");
+    }
+
+    /**
+     * Return the result of the given {@link CompletableFuture<T>}.
+     *
+     * <p>This method may throw exception is the task is completed with an error.</p>
+     *
+     * @param future the object to extract the result from.
+     * @param <T> type of the result.
+     * @return the result.
+     */
+    @AnyThread
+    @Nullable
+    public static <T> T getResult(@NonNull CompletableFuture<T> future) {
+        return getValueOrRethrowErrorInternal(future);
+    }
+
+    /**
+     * Return the result of the given {@link CompletableFuture<Boolean>}.
+     *
+     * <p>This method may throw exception is the task is completed with an error.</p>
+     *
+     * @param future the object to extract the result from.
+     * @return the result.
+     */
+    @AnyThread
+    public static boolean getBooleanResult(@NonNull CompletableFuture<Boolean> future) {
+        return getValueOrRethrowErrorInternal(future);
+    }
+
+    /**
+     * Return the result of the given {@link CompletableFuture<Integer>}.
+     *
+     * <p>This method may throw exception is the task is completed with an error.</p>
+     *
+     * @param future the object to extract the result from.
+     * @return the result.
+     */
+    @AnyThread
+    public static int getIntegerResult(@NonNull CompletableFuture<Integer> future) {
+        return getValueOrRethrowErrorInternal(future);
+    }
+
+    /**
+     * Return the result of the given {@link CompletableFuture<Boolean>}.
+     *
+     * <p>This method is agnostic to {@link Thread#interrupt()}.</p>
+     *
+     * <p>CAVEAT: when {@code cancellationGroup} is specified and it is signalled, {@code future}
+     * will be cancelled permanently.  You have to duplicate the {@link CompletableFuture} if you
+     * want to avoid this side-effect.</p>
+     *
+     * @param future the object to extract the result from.
+     * @param tag tag name for logging. Pass {@code null} to disable logging.
+     * @param methodName method name for logging. Pass {@code null} to disable logging.
+     * @param cancellationGroup an optional {@link CancellationGroup} to cancel {@code future}
+     *                          object. Can be {@code null}.
+     * @param timeoutMillis length of the timeout in millisecond.
+     * @return the result if it is completed within the given timeout. {@code false} otherwise.
+     */
+    @AnyThread
+    public static boolean getResultOrFalse(@NonNull CompletableFuture<Boolean> future,
+            @Nullable String tag, @Nullable String methodName,
+            @Nullable CancellationGroup cancellationGroup,
+            @DurationMillisLong long timeoutMillis) {
+        final Boolean obj = getValueOrNullInternal(future, tag, methodName, timeoutMillis,
+                cancellationGroup);
+        return obj != null ? obj : false;
+    }
+
+    /**
+     * Return the result of the given {@link CompletableFuture<Integer>}.
+     *
+     * <p>This method is agnostic to {@link Thread#interrupt()}.</p>
+     *
+     * <p>CAVEAT: when {@code cancellationGroup} is specified and it is signalled, {@code future}
+     * will be cancelled permanently.  You have to duplicate the {@link CompletableFuture} if you
+     * want to avoid this side-effect.</p>
+     *
+     * @param future the object to extract the result from.
+     * @param tag tag name for logging. Pass {@code null} to disable logging.
+     * @param methodName method name for logging. Pass {@code null} to disable logging.
+     * @param cancellationGroup an optional {@link CancellationGroup} to cancel {@code future}
+     *                          object. Can be {@code null}.
+     * @param timeoutMillis length of the timeout in millisecond.
+     * @return the result if it is completed within the given timeout. {@code 0} otherwise.
+     */
+    @AnyThread
+    public static int getResultOrZero(@NonNull CompletableFuture<Integer> future,
+            @Nullable String tag, @Nullable String methodName,
+            @Nullable CancellationGroup cancellationGroup, @DurationMillisLong long timeoutMillis) {
+        final Integer obj = getValueOrNullInternal(future, tag, methodName, timeoutMillis,
+                cancellationGroup);
+        return obj != null ? obj : 0;
+    }
+
+    /**
+     * Return the result of the given {@link CompletableFuture<T>}.
+     *
+     * <p>This method is agnostic to {@link Thread#interrupt()}.</p>
+     *
+     * <p>CAVEAT: when {@code cancellationGroup} is specified and it is signalled, {@code future}
+     * will be cancelled permanently.  You have to duplicate the {@link CompletableFuture} if you
+     * want to avoid this side-effect.</p>
+     *
+     * @param future the object to extract the result from.
+     * @param tag tag name for logging. Pass {@code null} to disable logging.
+     * @param methodName method name for logging. Pass {@code null} to disable logging.
+     * @param cancellationGroup an optional {@link CancellationGroup} to cancel {@code future}
+     *                          object. Can be {@code null}.
+     * @param timeoutMillis length of the timeout in millisecond.
+     * @param <T> Type of the result.
+     * @return the result if it is completed within the given timeout. {@code null} otherwise.
+     */
+    @AnyThread
+    @Nullable
+    public static <T> T getResultOrNull(@NonNull CompletableFuture<T> future, @Nullable String tag,
+            @Nullable String methodName, @Nullable CancellationGroup cancellationGroup,
+            @DurationMillisLong long timeoutMillis) {
+        return getValueOrNullInternal(future, tag, methodName, timeoutMillis, cancellationGroup);
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/IBooleanResultCallback.aidl b/core/java/com/android/internal/inputmethod/IBooleanResultCallback.aidl
deleted file mode 100644
index 6daeb3f..0000000
--- a/core/java/com/android/internal/inputmethod/IBooleanResultCallback.aidl
+++ /dev/null
@@ -1,24 +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.internal.inputmethod;
-
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IBooleanResultCallback {
-    void onResult(boolean result);
-    void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ICharSequenceResultCallback.aidl b/core/java/com/android/internal/inputmethod/ICharSequenceResultCallback.aidl
deleted file mode 100644
index da56fd0..0000000
--- a/core/java/com/android/internal/inputmethod/ICharSequenceResultCallback.aidl
+++ /dev/null
@@ -1,21 +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.internal.inputmethod;
-
-oneway interface ICharSequenceResultCallback {
-    void onResult(in CharSequence result);
-}
diff --git a/core/java/com/android/internal/inputmethod/IExtractedTextResultCallback.aidl b/core/java/com/android/internal/inputmethod/IExtractedTextResultCallback.aidl
deleted file mode 100644
index b603f6a..0000000
--- a/core/java/com/android/internal/inputmethod/IExtractedTextResultCallback.aidl
+++ /dev/null
@@ -1,23 +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.internal.inputmethod;
-
-import android.view.inputmethod.ExtractedText;
-
-oneway interface IExtractedTextResultCallback {
-    void onResult(in ExtractedText result);
-}
diff --git a/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
deleted file mode 100644
index 779acb5..0000000
--- a/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
+++ /dev/null
@@ -1,25 +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.internal.inputmethod;
-
-import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IInputContentUriTokenResultCallback {
-    void onResult(in IInputContentUriToken result);
-    void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
index 977f9a5..0cbdc13 100644
--- a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
+++ b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
@@ -23,16 +23,19 @@
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.SurroundingText;
 
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.view.IInputContext;
 
 import java.util.Objects;
 
 /**
  * A stateless wrapper of {@link com.android.internal.view.IInputContext} to encapsulate boilerplate
- * code around {@link Completable} and {@link RemoteException}.
+ * code around {@link AndroidFuture} and {@link RemoteException}.
  */
 public final class IInputContextInvoker {
 
@@ -60,19 +63,19 @@
      *
      * @param length {@code length} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
-     * @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.CharSequence getTextAfterCursor(int length, int flags) {
-        final Completable.CharSequence value = Completable.createCharSequence();
+    public AndroidFuture<CharSequence> getTextAfterCursor(int length, int flags) {
+        final AndroidFuture<CharSequence> future = new AndroidFuture<>();
         try {
-            mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
+            mIInputContext.getTextAfterCursor(length, flags, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
@@ -80,38 +83,38 @@
      *
      * @param length {@code length} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
-     * @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.CharSequence getTextBeforeCursor(int length, int flags) {
-        final Completable.CharSequence value = Completable.createCharSequence();
+    public AndroidFuture<CharSequence> getTextBeforeCursor(int length, int flags) {
+        final AndroidFuture<CharSequence> future = new AndroidFuture<>();
         try {
-            mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
+            mIInputContext.getTextBeforeCursor(length, flags, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
      * 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.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.CharSequence getSelectedText(int flags) {
-        final Completable.CharSequence value = Completable.createCharSequence();
+    public AndroidFuture<CharSequence> getSelectedText(int flags) {
+        final AndroidFuture<CharSequence> future = new AndroidFuture<>();
         try {
-            mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
+            mIInputContext.getSelectedText(flags, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
@@ -121,40 +124,39 @@
      * @param beforeLength {@code beforeLength} parameter to be passed.
      * @param afterLength {@code afterLength} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
-     * @return {@link Completable.SurroundingText} that can be used to retrieve the invocation
-     *         result. {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<SurroundingText>} that can be used to retrieve the
+     *         invocation result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.SurroundingText getSurroundingText(int beforeLength, int afterLength,
+    public AndroidFuture<SurroundingText> getSurroundingText(int beforeLength, int afterLength,
             int flags) {
-        final Completable.SurroundingText value = Completable.createSurroundingText();
+        final AndroidFuture<SurroundingText> future = new AndroidFuture<>();
         try {
-            mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
-                    ResultCallbacks.of(value));
+            mIInputContext.getSurroundingText(beforeLength, afterLength, flags, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
      * 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.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<Integer>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.Int getCursorCapsMode(int reqModes) {
-        final Completable.Int value = Completable.createInt();
+    public AndroidFuture<Integer> getCursorCapsMode(int reqModes) {
+        final AndroidFuture<Integer> future = new AndroidFuture<>();
         try {
-            mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
+            mIInputContext.getCursorCapsMode(reqModes, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
@@ -163,19 +165,20 @@
      *
      * @param request {@code request} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
-     * @return {@link Completable.ExtractedText} that can be used to retrieve the invocation result.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<ExtractedText>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
-        final Completable.ExtractedText value = Completable.createExtractedText();
+    public AndroidFuture<ExtractedText> getExtractedText(ExtractedTextRequest request,
+            int flags) {
+        final AndroidFuture<ExtractedText> future = new AndroidFuture<>();
         try {
-            mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
+            mIInputContext.getExtractedText(request, flags, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
@@ -474,19 +477,19 @@
      * 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.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.Boolean requestCursorUpdates(int cursorUpdateMode) {
-        final Completable.Boolean value = Completable.createBoolean();
+    public AndroidFuture<Boolean> requestCursorUpdates(int cursorUpdateMode) {
+        final AndroidFuture<Boolean> future = new AndroidFuture<>();
         try {
-            mIInputContext.requestCursorUpdates(cursorUpdateMode, ResultCallbacks.of(value));
+            mIInputContext.requestCursorUpdates(cursorUpdateMode, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
@@ -496,20 +499,20 @@
      * @param inputContentInfo {@code inputContentInfo} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
      * @param opts {@code opts} parameter to be passed.
-     * @return {@link Completable.Boolean} that can be used to retrieve the invocation result.
-     *         {@link RemoteException} will be treated as an error.
+     * @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
+     *         result. {@link RemoteException} will be treated as an error.
      */
     @AnyThread
     @NonNull
-    public Completable.Boolean commitContent(InputContentInfo inputContentInfo, int flags,
+    public AndroidFuture<Boolean> commitContent(InputContentInfo inputContentInfo, int flags,
             Bundle opts) {
-        final Completable.Boolean value = Completable.createBoolean();
+        final AndroidFuture<Boolean> future = new AndroidFuture<>();
         try {
-            mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
+            mIInputContext.commitContent(inputContentInfo, flags, opts, future);
         } catch (RemoteException e) {
-            value.onError(ThrowableHolder.of(e));
+            future.completeExceptionally(e);
         }
-        return value;
+        return future;
     }
 
     /**
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 36943e3..9d0f209 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -19,10 +19,7 @@
 import android.net.Uri;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.internal.inputmethod.IBooleanResultCallback;
-import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
-import com.android.internal.inputmethod.IVoidResultCallback;
+import com.android.internal.infra.AndroidFuture;
 
 /**
  * Defines priviledged operations that only the current IME is allowed to call.
@@ -32,17 +29,17 @@
     void setImeWindowStatusAsync(int vis, int backDisposition);
     void reportStartInputAsync(in IBinder startInputToken);
     void createInputContentUriToken(in Uri contentUri, in String packageName,
-            in IInputContentUriTokenResultCallback resultCallback);
+            in AndroidFuture future /* T=IBinder */);
     void reportFullscreenModeAsync(boolean fullscreen);
-    void setInputMethod(String id, in IVoidResultCallback resultCallback);
+    void setInputMethod(String id, in AndroidFuture future /* T=Void */);
     void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
-            in IVoidResultCallback resultCallback);
-    void hideMySoftInput(int flags, in IVoidResultCallback resultCallback);
-    void showMySoftInput(int flags, in IVoidResultCallback resultCallback);
+            in AndroidFuture future /* T=Void */);
+    void hideMySoftInput(int flags, in AndroidFuture future /* T=Void */);
+    void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
     void updateStatusIconAsync(String packageName, int iconId);
-    void switchToPreviousInputMethod(in IBooleanResultCallback resultCallback);
-    void switchToNextInputMethod(boolean onlyCurrentIme, in IBooleanResultCallback resultCallback);
-    void shouldOfferSwitchingToNextInputMethod(in IBooleanResultCallback resultCallback);
+    void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
+    void switchToNextInputMethod(boolean onlyCurrentIme, in AndroidFuture future /* T=Boolean */);
+    void shouldOfferSwitchingToNextInputMethod(in AndroidFuture future /* T=Boolean */);
     void notifyUserActionAsync();
     void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible);
 }
diff --git a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl b/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
deleted file mode 100644
index ceda66c..0000000
--- a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
+++ /dev/null
@@ -1,24 +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.internal.inputmethod;
-
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IIntResultCallback {
-    void onResult(int result);
-    void onError(in ThrowableHolder exception);
-}
diff --git a/core/java/com/android/internal/inputmethod/ISurroundingTextResultCallback.aidl b/core/java/com/android/internal/inputmethod/ISurroundingTextResultCallback.aidl
deleted file mode 100644
index 6c4f3d5..0000000
--- a/core/java/com/android/internal/inputmethod/ISurroundingTextResultCallback.aidl
+++ /dev/null
@@ -1,23 +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.internal.inputmethod;
-
-import android.view.inputmethod.SurroundingText;
-
-oneway interface ISurroundingTextResultCallback {
-    void onResult(in SurroundingText result);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl b/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl
deleted file mode 100644
index 0b25a2b..0000000
--- a/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl
+++ /dev/null
@@ -1,24 +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.internal.inputmethod;
-
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IVoidResultCallback {
-    void onResult();
-    void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 9fb0bb5..d4cc376 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -28,6 +28,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
 
 import java.util.Objects;
 
@@ -142,7 +143,7 @@
 
     /**
      * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
-     * IInputContentUriTokenResultCallback)}.
+     * AndroidFuture)}.
      *
      * @param contentUri Content URI to which a temporary read permission should be granted
      * @param packageName Indicates what package needs to have a temporary read permission
@@ -156,10 +157,9 @@
             return null;
         }
         try {
-            final Completable.IInputContentUriToken value =
-                    Completable.createIInputContentUriToken();
-            ops.createInputContentUriToken(contentUri, packageName, ResultCallbacks.of(value));
-            return Completable.getResult(value);
+            final AndroidFuture<IBinder> future = new AndroidFuture<>();
+            ops.createInputContentUriToken(contentUri, packageName, future);
+            return IInputContentUriToken.Stub.asInterface(CompletableFutureUtil.getResult(future));
         } catch (RemoteException e) {
             // For historical reasons, this error was silently ignored.
             // Note that the caller already logs error so we do not need additional Log.e() here.
@@ -206,7 +206,7 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, IVoidResultCallback)}.
+     * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, AndroidFuture)}.
      *
      * @param id IME ID of the IME to switch to
      * @see android.view.inputmethod.InputMethodInfo#getId()
@@ -218,9 +218,9 @@
             return;
         }
         try {
-            final Completable.Void value = Completable.createVoid();
-            ops.setInputMethod(id, ResultCallbacks.of(value));
-            Completable.getResult(value);
+            final AndroidFuture<Void> future = new AndroidFuture<>();
+            ops.setInputMethod(id, future);
+            CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -228,7 +228,7 @@
 
     /**
      * Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
-     * InputMethodSubtype, IVoidResultCallback)}
+     * InputMethodSubtype, AndroidFuture)}
      *
      * @param id IME ID of the IME to switch to
      * @param subtype {@link InputMethodSubtype} to switch to
@@ -241,9 +241,9 @@
             return;
         }
         try {
-            final Completable.Void value = Completable.createVoid();
-            ops.setInputMethodAndSubtype(id, subtype, ResultCallbacks.of(value));
-            Completable.getResult(value);
+            final AndroidFuture<Void> future = new AndroidFuture<>();
+            ops.setInputMethodAndSubtype(id, subtype, future);
+            CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -263,16 +263,16 @@
             return;
         }
         try {
-            final Completable.Void value = Completable.createVoid();
-            ops.hideMySoftInput(flags, ResultCallbacks.of(value));
-            Completable.getResult(value);
+            final AndroidFuture<Void> future = new AndroidFuture<>();
+            ops.hideMySoftInput(flags, future);
+            CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, IVoidResultCallback)}
+     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, AndroidFuture)}
      *
      * @param flags additional operating flags
      * @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
@@ -285,17 +285,16 @@
             return;
         }
         try {
-            final Completable.Void value = Completable.createVoid();
-            ops.showMySoftInput(flags, ResultCallbacks.of(value));
-            Completable.getResult(value);
+            final AndroidFuture<Void> future = new AndroidFuture<>();
+            ops.showMySoftInput(flags, future);
+            CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(
-     * IBooleanResultCallback)}
+     * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(AndroidFuture)}
      *
      * @return {@code true} if handled
      */
@@ -306,9 +305,9 @@
             return false;
         }
         try {
-            final Completable.Boolean value = Completable.createBoolean();
-            ops.switchToPreviousInputMethod(ResultCallbacks.of(value));
-            return Completable.getResult(value);
+            final AndroidFuture<Boolean> value = new AndroidFuture<>();
+            ops.switchToPreviousInputMethod(value);
+            return CompletableFutureUtil.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -329,9 +328,9 @@
             return false;
         }
         try {
-            final Completable.Boolean value = Completable.createBoolean();
-            ops.switchToNextInputMethod(onlyCurrentIme, ResultCallbacks.of(value));
-            return Completable.getResult(value);
+            final AndroidFuture<Boolean> future = new AndroidFuture<>();
+            ops.switchToNextInputMethod(onlyCurrentIme, future);
+            return CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -339,7 +338,7 @@
 
     /**
      * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod(
-     * IBooleanResultCallback)}
+     * AndroidFuture)}
      *
      * @return {@code true} if the IEM should offer a way to globally switch IME
      */
@@ -350,9 +349,9 @@
             return false;
         }
         try {
-            final Completable.Boolean value = Completable.createBoolean();
-            ops.shouldOfferSwitchingToNextInputMethod(ResultCallbacks.of(value));
-            return Completable.getResult(value);
+            final AndroidFuture<Boolean> future = new AndroidFuture<>();
+            ops.shouldOfferSwitchingToNextInputMethod(future);
+            return CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index d1bca85..662bd28 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -21,7 +21,6 @@
 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;
@@ -40,9 +39,11 @@
 import android.view.inputmethod.SurroundingText;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.view.IInputContext;
 
 import java.lang.ref.WeakReference;
+import java.util.function.Supplier;
 
 /**
  * Takes care of remote method invocations of {@link InputConnection} in the IME client side.
@@ -86,13 +87,17 @@
      * @return {@link InputConnection} to which incoming IPCs will be dispatched.
      */
     @Nullable
-    public InputConnection getInputConnection() {
+    private InputConnection getInputConnection() {
         synchronized (mLock) {
             return mInputConnection;
         }
     }
 
-    private boolean isFinished() {
+    /**
+     * @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;
         }
@@ -117,25 +122,54 @@
             // reportFinish() will take effect.
             return;
         }
-        closeConnection();
-
-        // 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);
+        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;
                 }
-                if (handler.getLooper().isCurrentThread()) {
-                    servedView.onInputConnectionClosedInternal();
-                } else {
-                    handler.post(servedView::onInputConnectionClosedInternal);
+                @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
@@ -169,600 +203,407 @@
         }
     }
 
-    @Override
-    public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
+    /**
+     * 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(() -> {
-            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);
+            final InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                return;
             }
+            ic.reportFullscreenMode(enabled);
         });
     }
 
     @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);
+    public void getTextAfterCursor(int length, int flags,
+            AndroidFuture future /* T=CharSequence */) {
+        dispatchWithTracing("getTextAfterCursor", future, () -> {
+            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);
+            }
+            return result;
         });
     }
 
     @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);
+    public void getTextBeforeCursor(int length, int flags,
+            AndroidFuture future /* T=CharSequence */) {
+        dispatchWithTracing("getTextBeforeCursor", future, () -> {
+            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);
+            }
+            return result;
+        });
+    }
+
+    @Override
+    public void getSelectedText(int flags, AndroidFuture future /* T=CharSequence */) {
+        dispatchWithTracing("getSelectedText", future, () -> {
+            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);
+            }
+            return result;
         });
     }
 
     @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);
+            AndroidFuture future /* T=SurroundingText */) {
+        dispatchWithTracing("getSurroundingText", future, () -> {
+            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);
+            }
+            return result;
         });
     }
 
     @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);
+    public void getCursorCapsMode(int reqModes, AndroidFuture future /* T=Integer */) {
+        dispatchWithTracing("getCursorCapsMode", future, () -> {
+            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);
+            }
+            return result;
         });
     }
 
     @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);
+            AndroidFuture future /* T=ExtractedText */) {
+        dispatchWithTracing("getExtractedText", future, () -> {
+            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);
+            }
+            return result;
         });
     }
 
     @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);
+        dispatchWithTracing("commitText", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "commitText on inactive InputConnection");
+                return;
             }
+            ic.commitText(text, newCursorPosition);
         });
     }
 
     @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);
+        dispatchWithTracing("commitCompletion", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "commitCompletion on inactive InputConnection");
+                return;
             }
+            ic.commitCompletion(text);
         });
     }
 
     @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);
+        dispatchWithTracing("commitCorrection", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "commitCorrection on inactive InputConnection");
+                return;
             }
+            ic.commitCorrection(info);
         });
     }
 
     @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);
+        dispatchWithTracing("setSelection", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "setSelection on inactive InputConnection");
+                return;
             }
+            ic.setSelection(start, end);
         });
     }
 
     @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);
+        dispatchWithTracing("performEditorAction", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "performEditorAction on inactive InputConnection");
+                return;
             }
+            ic.performEditorAction(id);
         });
     }
 
     @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);
+        dispatchWithTracing("performContextMenuAction", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+                return;
             }
+            ic.performContextMenuAction(id);
         });
     }
 
     @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);
+        dispatchWithTracing("setComposingRegion", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "setComposingRegion on inactive InputConnection");
+                return;
             }
+            ic.setComposingRegion(start, end);
         });
     }
 
     @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);
+        dispatchWithTracing("setComposingText", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "setComposingText on inactive InputConnection");
+                return;
             }
+            ic.setComposingText(text, newCursorPosition);
         });
     }
 
     @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;
+        dispatchWithTracing("finishComposingText", () -> {
+            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.");
                 }
-                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;
             }
+            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();
         });
     }
 
     @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);
+        dispatchWithTracing("sendKeyEvent", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+                return;
             }
+            ic.sendKeyEvent(event);
         });
     }
 
     @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);
+        dispatchWithTracing("clearMetaKeyStates", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+                return;
             }
+            ic.clearMetaKeyStates(states);
         });
     }
 
     @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);
+        dispatchWithTracing("deleteSurroundingText", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+                return;
             }
+            ic.deleteSurroundingText(beforeLength, afterLength);
         });
     }
 
     @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);
+        dispatchWithTracing("deleteSurroundingTextInCodePoints", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
+                return;
             }
+            ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
         });
     }
 
     @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);
+        dispatchWithTracing("beginBatchEdit", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+                return;
             }
+            ic.beginBatchEdit();
         });
     }
 
     @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);
+        dispatchWithTracing("endBatchEdit", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "endBatchEdit on inactive InputConnection");
+                return;
             }
+            ic.endBatchEdit();
         });
     }
 
     @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);
+        dispatchWithTracing("performSpellCheck", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "performSpellCheck on inactive InputConnection");
+                return;
             }
+            ic.performSpellCheck();
         });
     }
 
     @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);
+        dispatchWithTracing("performPrivateCommand", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "performPrivateCommand on inactive InputConnection");
+                return;
             }
+            ic.performPrivateCommand(action, data);
         });
     }
 
     @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);
+    public void requestCursorUpdates(int cursorUpdateMode, AndroidFuture future /* T=Boolean */) {
+        dispatchWithTracing("requestCursorUpdates", future, () -> {
+            final InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
+                return false;
             }
-        });
-    }
-
-    private void closeConnection() {
-        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);
-            }
+            return ic.requestCursorUpdates(cursorUpdateMode);
         });
     }
 
     @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);
+            AndroidFuture future /* T=Boolean */) {
+        dispatchWithTracing("commitContent", future, () -> {
+            final InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "commitContent on inactive InputConnection");
+                return false;
             }
+            if (inputContentInfo == null || !inputContentInfo.validate()) {
+                Log.w(TAG, "commitContent with invalid inputContentInfo=" + inputContentInfo);
+                return false;
+            }
+            return ic.commitContent(inputContentInfo, flags, opts);
         });
     }
 
     @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);
+        dispatchWithTracing("setImeConsumesInput", () -> {
+            InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                Log.w(TAG, "setImeConsumesInput on inactive InputConnection");
+                return;
             }
+            ic.setImeConsumesInput(imeConsumesInput);
         });
     }
 
@@ -776,4 +617,38 @@
 
         mH.post(runnable);
     }
+
+    private void dispatchWithTracing(@NonNull String methodName, @NonNull Runnable runnable) {
+        final Runnable actualRunnable;
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_INPUT)) {
+            actualRunnable = () -> {
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#" + methodName);
+                try {
+                    runnable.run();
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+                }
+            };
+        } else {
+            actualRunnable = runnable;
+        }
+
+        dispatch(actualRunnable);
+    }
+
+    private <T> void dispatchWithTracing(@NonNull String methodName,
+            @NonNull AndroidFuture untypedFuture, @NonNull Supplier<T> supplier) {
+        @SuppressWarnings("unchecked")
+        final AndroidFuture<T> future = untypedFuture;
+        dispatchWithTracing(methodName, () -> {
+            final T result;
+            try {
+                result = supplier.get();
+            } catch (Throwable throwable) {
+                future.completeExceptionally(throwable);
+                throw throwable;
+            }
+            future.complete(result);
+        });
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
deleted file mode 100644
index 343a6e6..0000000
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ /dev/null
@@ -1,261 +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.internal.inputmethod;
-
-import android.annotation.AnyThread;
-import android.annotation.BinderThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Defines a set of factory methods to create {@link android.os.IBinder}-based callbacks that are
- * associated with completable objects defined in {@link Completable}.
- */
-public final class ResultCallbacks {
-
-    /**
-     * Not intended to be instantiated.
-     */
-    private ResultCallbacks() {
-    }
-
-    @AnyThread
-    @Nullable
-    private static <T> T unwrap(@NonNull AtomicReference<T> atomicRef) {
-        // Only the first caller will receive the non-null original object.
-        return atomicRef.getAndSet(null);
-    }
-
-    /**
-     * Creates {@link IIntResultCallback.Stub} that is to set {@link Completable.Int} when receiving
-     * the result.
-     *
-     * @param value {@link Completable.Int} to be set when receiving the result.
-     * @return {@link IIntResultCallback.Stub} that can be passed as a binder IPC parameter.
-     */
-    @AnyThread
-    public static IIntResultCallback.Stub of(@NonNull Completable.Int value) {
-        final AtomicReference<Completable.Int> atomicRef = new AtomicReference<>(value);
-
-        return new IIntResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult(int result) {
-                final Completable.Int value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete(result);
-            }
-
-            @BinderThread
-            @Override
-            public void onError(ThrowableHolder throwableHolder) {
-                final Completable.Int value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onError(throwableHolder);
-            }
-        };
-    }
-
-    /**
-     * Creates {@link ICharSequenceResultCallback.Stub} that is to set
-     * {@link Completable.CharSequence} when receiving the result.
-     *
-     * @param value {@link Completable.CharSequence} to be set when receiving the result.
-     * @return {@link ICharSequenceResultCallback.Stub} that can be passed as a binder IPC
-     *         parameter.
-     */
-    @AnyThread
-    public static ICharSequenceResultCallback.Stub of(
-            @NonNull Completable.CharSequence value) {
-        final AtomicReference<Completable.CharSequence> atomicRef = new AtomicReference<>(value);
-
-        return new ICharSequenceResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult(CharSequence result) {
-                final Completable.CharSequence value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete(result);
-            }
-        };
-    }
-
-    /**
-     * Creates {@link IExtractedTextResultCallback.Stub} that is to set
-     * {@link Completable.ExtractedText} when receiving the result.
-     *
-     * @param value {@link Completable.ExtractedText} to be set when receiving the result.
-     * @return {@link IExtractedTextResultCallback.Stub} that can be passed as a binder IPC
-     *         parameter.
-     */
-    @AnyThread
-    public static IExtractedTextResultCallback.Stub of(
-            @NonNull Completable.ExtractedText value) {
-        final AtomicReference<Completable.ExtractedText> atomicRef = new AtomicReference<>(value);
-
-        return new IExtractedTextResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult(android.view.inputmethod.ExtractedText result) {
-                final Completable.ExtractedText value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete(result);
-            }
-        };
-    }
-
-    /**
-     * Creates {@link ISurroundingTextResultCallback.Stub} that is to set
-     * {@link Completable.SurroundingText} when receiving the result.
-     *
-     * @param value {@link Completable.SurroundingText} to be set when receiving the result.
-     * @return {@link ISurroundingTextResultCallback.Stub} that can be passed as a binder IPC
-     *         parameter.
-     */
-    @AnyThread
-    public static ISurroundingTextResultCallback.Stub of(
-            @NonNull Completable.SurroundingText value) {
-        final AtomicReference<Completable.SurroundingText> atomicRef = new AtomicReference<>(value);
-
-        return new ISurroundingTextResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult(android.view.inputmethod.SurroundingText result) {
-                final Completable.SurroundingText value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete(result);
-            }
-        };
-    }
-
-    /**
-     * Creates {@link IBooleanResultCallback.Stub} that is to set {@link Completable.Boolean} when
-     * receiving the result.
-     *
-     * @param value {@link Completable.Boolean} to be set when receiving the result.
-     * @return {@link IBooleanResultCallback.Stub} that can be passed as a binder IPC parameter.
-     */
-    @AnyThread
-    public static IBooleanResultCallback.Stub of(@NonNull Completable.Boolean value) {
-        final AtomicReference<Completable.Boolean> atomicRef = new AtomicReference<>(value);
-
-        return new IBooleanResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult(boolean result) {
-                final Completable.Boolean value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete(result);
-            }
-
-            @BinderThread
-            @Override
-            public void onError(ThrowableHolder throwableHolder) {
-                final Completable.Boolean value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onError(throwableHolder);
-            }
-        };
-    }
-
-    /**
-     * Creates {@link IVoidResultCallback.Stub} that is to set {@link Completable.Void} when
-     * receiving the result.
-     *
-     * @param value {@link Completable.Void} to be set when receiving the result.
-     * @return {@link IVoidResultCallback.Stub} that can be passed as a binder IPC parameter.
-     */
-    @AnyThread
-    public static IVoidResultCallback.Stub of(@NonNull Completable.Void value) {
-        final AtomicReference<Completable.Void> atomicRef = new AtomicReference<>(value);
-
-        return new IVoidResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult() {
-                final Completable.Void value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete();
-            }
-
-            @BinderThread
-            @Override
-            public void onError(ThrowableHolder throwableHolder) {
-                final Completable.Void value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onError(throwableHolder);
-            }
-        };
-    }
-
-    /**
-     * Creates {@link IInputContentUriTokenResultCallback.Stub} that is to set
-     * {@link Completable.IInputContentUriToken} when receiving the result.
-     *
-     * @param value {@link Completable.IInputContentUriToken} to be set when receiving the result.
-     * @return {@link IInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
-     * parameter.
-     */
-    @AnyThread
-    public static IInputContentUriTokenResultCallback.Stub of(
-            @NonNull Completable.IInputContentUriToken value) {
-        final AtomicReference<Completable.IInputContentUriToken>
-                atomicRef = new AtomicReference<>(value);
-
-        return new IInputContentUriTokenResultCallback.Stub() {
-            @BinderThread
-            @Override
-            public void onResult(IInputContentUriToken result) {
-                final Completable.IInputContentUriToken value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onComplete(result);
-            }
-
-            @BinderThread
-            @Override
-            public void onError(ThrowableHolder throwableHolder) {
-                final Completable.IInputContentUriToken value = unwrap(atomicRef);
-                if (value == null) {
-                    return;
-                }
-                value.onError(throwableHolder);
-            }
-        };
-    }
-}
diff --git a/core/java/com/android/internal/inputmethod/ThrowableHolder.aidl b/core/java/com/android/internal/inputmethod/ThrowableHolder.aidl
deleted file mode 100644
index ed11293..0000000
--- a/core/java/com/android/internal/inputmethod/ThrowableHolder.aidl
+++ /dev/null
@@ -1,19 +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.inputmethod;
-
-parcelable ThrowableHolder;
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ThrowableHolder.java b/core/java/com/android/internal/inputmethod/ThrowableHolder.java
deleted file mode 100644
index b6f4498..0000000
--- a/core/java/com/android/internal/inputmethod/ThrowableHolder.java
+++ /dev/null
@@ -1,91 +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.internal.inputmethod;
-
-import android.annotation.AnyThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A {@link Parcelable} helper class to encapsulate the exception information.
- */
-public final class ThrowableHolder implements Parcelable {
-
-    @Nullable
-    private final String mMessage;
-
-    ThrowableHolder(@NonNull Throwable throwable) {
-        mMessage = throwable.getMessage();
-    }
-
-    ThrowableHolder(Parcel source) {
-        mMessage = source.readString();
-    }
-
-    /**
-     * Returns a {@link ThrowableHolder} with given {@link Throwable}.
-     */
-    @NonNull
-    @AnyThread
-    public static ThrowableHolder of(@NonNull Throwable throwable) {
-        return new ThrowableHolder(throwable);
-    }
-
-    /**
-     * Gets the message in this {@link ThrowableHolder}.
-     */
-    @Nullable
-    @AnyThread
-    String getMessage() {
-        return mMessage;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Used to package this object into a {@link Parcel}.
-     *
-     * @param dest The {@link Parcel} to be written.
-     * @param flags The flags used for parceling.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mMessage);
-    }
-
-    /**
-     * Used to make this class parcelable.
-     */
-    public static final Parcelable.Creator<ThrowableHolder> CREATOR =
-            new Parcelable.Creator<ThrowableHolder>() {
-
-        @Override
-        public ThrowableHolder createFromParcel(Parcel source) {
-            return new ThrowableHolder(source);
-        }
-
-        @Override
-        public ThrowableHolder[] newArray(int size) {
-            return new ThrowableHolder[size];
-        }
-    };
-}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index aa7142e..66c0ce2 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -51,6 +51,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A class that allows the app to get the frame metrics from HardwareRendererObserver.
@@ -108,6 +109,7 @@
     private boolean mCancelled = false;
     private FrameTrackerListener mListener;
     private boolean mTracingStarted = false;
+    private Runnable mWaitForFinishTimedOut;
 
     private static class JankInfo {
         long frameVsyncId;
@@ -174,52 +176,51 @@
             // 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();
-                                }
+            }
+
+            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 surfaceReplaced(SurfaceControl.Transaction t) {
+                }
 
-                    @Override
-                    public void surfaceDestroyed() {
+                @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);
-                                }
+                    // 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);
                             }
-                        }, 50);
-                    }
-                };
-                // This callback has a reference to FrameTracker,
-                // remember to remove it to avoid leakage.
-                mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback);
-            }
+                            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);
         }
     }
 
@@ -283,10 +284,17 @@
             if (mListener != null) {
                 mListener.onCujEvents(mSession, ACTION_SESSION_END);
             }
+
+            // We don't remove observer here,
+            // will remove it when all the frame metrics in this duration are called back.
+            // See onFrameMetricsAvailable for the logic of removing the observer.
+            // Let's wait for all callbacks to finish for at most a minute.
+            mWaitForFinishTimedOut = () -> {
+                Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
+                finish(mJankInfos.size() - 1);
+            };
+            mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.MINUTES.toMillis(1));
         }
-        // We don't remove observer here,
-        // will remove it when all the frame metrics in this duration are called back.
-        // See onFrameMetricsAvailable for the logic of removing the observer.
     }
 
     /**
@@ -423,7 +431,8 @@
     }
 
     private void finish(int indexOnOrAfterEnd) {
-
+        mHandler.removeCallbacks(mWaitForFinishTimedOut);
+        mWaitForFinishTimedOut = null;
         mMetricsFinalized = true;
 
         // The tracing has been ended, remove the observer, see if need to trigger perfetto.
@@ -509,7 +518,7 @@
             }
         }
         if (DEBUG) {
-            Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
+            Log.i(TAG, "finish: CUJ=" + mSession.getName()
                     + " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
                     + " totalFrames=" + totalFramesCount
                     + " missedAppFrames=" + missedAppFramesCount
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index 5212265..2f4a14f 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -32,6 +32,22 @@
      * OEMs should use event IDs above 100000 and below 1000000 (1 million).
      */
     interface UiEventEnum {
+
+        /**
+         * Tag used to request new UI Event IDs via presubmit analysis.
+         *
+         * <p>Use RESERVE_NEW_UI_EVENT_ID as the constructor parameter for a new {@link EventEnum}
+         * to signal the presubmit analyzer to reserve a new ID for the event. The new ID will be
+         * returned as a Gerrit presubmit finding.  Do not submit {@code RESERVE_NEW_UI_EVENT_ID} as
+         * the constructor parameter for any event.
+         *
+         * <pre>
+         * &#064;UiEvent(doc = "Briefly describe the interaction when this event will be logged")
+         * UNIQUE_EVENT_NAME(RESERVE_NEW_UI_EVENT_ID);
+         * </pre>
+         */
+        int RESERVE_NEW_UI_EVENT_ID = Integer.MIN_VALUE; // Negative IDs are ignored by the logger.
+
         int getId();
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4043060..719dc53 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -661,6 +661,10 @@
      * Mapping isolated uids to the actual owning app uid.
      */
     final SparseIntArray mIsolatedUids = new SparseIntArray();
+    /**
+     * Internal reference count of isolated uids.
+     */
+    final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray();
 
     /**
      * The statistics we have collected organized by uids.
@@ -3855,6 +3859,7 @@
     public void addIsolatedUidLocked(int isolatedUid, int appUid,
             long elapsedRealtimeMs, long uptimeMs) {
         mIsolatedUids.put(isolatedUid, appUid);
+        mIsolatedUidRefCounts.put(isolatedUid, 1);
         final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
         u.addIsolatedUid(isolatedUid);
     }
@@ -3873,19 +3878,51 @@
     }
 
     /**
-     * This should only be called after the cpu times have been read.
+     * Isolated uid should only be removed after all wakelocks associated with the uid are stopped
+     * and the cpu time-in-state has been read one last time for the uid.
+     *
      * @see #scheduleRemoveIsolatedUidLocked(int, int)
+     *
+     * @return true if the isolated uid is actually removed.
      */
     @GuardedBy("this")
-    public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
+    public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs,
+            long uptimeMs) {
+        final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1;
+        if (refCount > 0) {
+            // Isolated uid is still being tracked
+            mIsolatedUidRefCounts.put(isolatedUid, refCount);
+            return false;
+        }
+
         final int idx = mIsolatedUids.indexOfKey(isolatedUid);
         if (idx >= 0) {
             final int ownerUid = mIsolatedUids.valueAt(idx);
             final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
             u.removeIsolatedUid(isolatedUid);
             mIsolatedUids.removeAt(idx);
+            mIsolatedUidRefCounts.delete(isolatedUid);
+        } else {
+            Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")");
         }
         mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
+
+        return true;
+    }
+
+    /**
+     * Increment the ref count for an isolated uid.
+     * call #maybeRemoveIsolatedUidLocked to decrement.
+     */
+    public void incrementIsolatedUidRefCount(int uid) {
+        final int refCount = mIsolatedUidRefCounts.get(uid, 0);
+        if (refCount <= 0) {
+            // Uid is not mapped or referenced
+            Slog.w(TAG,
+                    "Attempted to increment ref counted of untracked isolated uid (" + uid + ")");
+            return;
+        }
+        mIsolatedUidRefCounts.put(uid, refCount + 1);
     }
 
     public int mapUid(int uid) {
@@ -4245,7 +4282,7 @@
 
     public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
             int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
-        uid = mapUid(uid);
+        final int mappedUid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
             // will be canceled when the user puts the screen to sleep.
@@ -4255,9 +4292,9 @@
             }
             if (mRecordAllHistory) {
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
-                        uid, 0)) {
+                        mappedUid, 0)) {
                     addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
-                            HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
+                            HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid);
                 }
             }
             if (mWakeLockNesting == 0) {
@@ -4266,7 +4303,7 @@
                         + Integer.toHexString(mHistoryCur.states));
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
-                mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
+                mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
                 mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             } else if (!mWakeLockImportant && !unimportantForLogging
@@ -4276,14 +4313,19 @@
                     mHistoryLastWritten.wakelockTag = null;
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                     mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
-                    mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
+                    mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
                     addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
                 }
                 mWakeLockImportant = true;
             }
             mWakeLockNesting++;
         }
-        if (uid >= 0) {
+        if (mappedUid >= 0) {
+            if (mappedUid != uid) {
+                // Prevent the isolated uid mapping from being removed while the wakelock is
+                // being held.
+                incrementIsolatedUidRefCount(uid);
+            }
             if (mOnBatteryScreenOffTimeBase.isRunning()) {
                 // We only update the cpu time when a wake lock is acquired if the screen is off.
                 // If the screen is on, we don't distribute the power amongst partial wakelocks.
@@ -4293,7 +4335,7 @@
                 requestWakelockCpuUpdate();
             }
 
-            getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+            getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
                     .noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
 
             if (wc != null) {
@@ -4301,8 +4343,8 @@
                         wc.getTags(), getPowerManagerWakeLockLevel(type), name,
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
             } else {
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
-                        null, getPowerManagerWakeLockLevel(type), name,
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
+                        mappedUid, null, getPowerManagerWakeLockLevel(type), name,
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
             }
         }
@@ -4316,7 +4358,7 @@
 
     public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
             int type, long elapsedRealtimeMs, long uptimeMs) {
-        uid = mapUid(uid);
+        final int mappedUid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
             if (mRecordAllHistory) {
@@ -4324,9 +4366,9 @@
                     historyName = name;
                 }
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
-                        uid, 0)) {
+                        mappedUid, 0)) {
                     addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
-                            HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
+                            HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid);
                 }
             }
             if (mWakeLockNesting == 0) {
@@ -4338,7 +4380,7 @@
                 addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             }
         }
-        if (uid >= 0) {
+        if (mappedUid >= 0) {
             if (mOnBatteryScreenOffTimeBase.isRunning()) {
                 if (DEBUG_ENERGY_CPU) {
                     Slog.d(TAG, "Updating cpu time because of -wake_lock");
@@ -4346,17 +4388,22 @@
                 requestWakelockCpuUpdate();
             }
 
-            getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+            getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
                     .noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
             if (wc != null) {
                 FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
                         wc.getTags(), getPowerManagerWakeLockLevel(type), name,
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
             } else {
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
-                        null, getPowerManagerWakeLockLevel(type), name,
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
+                        mappedUid, null, getPowerManagerWakeLockLevel(type), name,
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
             }
+
+            if (mappedUid != uid) {
+                // Decrement the ref count for the isolated uid and delete the mapping if uneeded.
+                maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs);
+            }
         }
     }
 
@@ -16769,6 +16816,15 @@
         pw.print("UIDs removed since the later of device start or stats reset: ");
         pw.println(mNumUidsRemoved);
 
+        pw.println("Currently mapped isolated uids:");
+        final int numIsolatedUids = mIsolatedUids.size();
+        for (int i = 0; i < numIsolatedUids; i++) {
+            final int isolatedUid = mIsolatedUids.keyAt(i);
+            final int ownerUid = mIsolatedUids.valueAt(i);
+            final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
+            pw.println("  " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
+        }
+
         pw.println();
         dumpConstantsLocked(pw);
 
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index c0a22e0..e9e489d 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -29,6 +29,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -234,8 +235,9 @@
         final boolean includePowerModels = (query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
 
+        final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames();
         final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                mStats.getCustomEnergyConsumerNames(), includePowerModels);
+                customEnergyConsumerNames, includePowerModels);
         if (mBatteryUsageStatsStore == null) {
             Log.e(TAG, "BatteryUsageStatsStore is unavailable");
             return builder.build();
@@ -247,7 +249,14 @@
                 final BatteryUsageStats snapshot =
                         mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
                 if (snapshot != null) {
-                    builder.add(snapshot);
+                    if (Arrays.equals(snapshot.getCustomPowerComponentNames(),
+                            customEnergyConsumerNames)) {
+                        builder.add(snapshot);
+                    } else {
+                        Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different "
+                                + "custom power components: "
+                                + Arrays.toString(snapshot.getCustomPowerComponentNames()));
+                    }
                 }
             }
         }
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
new file mode 100644
index 0000000..1a3b29d
--- /dev/null
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -0,0 +1,181 @@
+/*
+ * 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 dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Performs per-state counting of multi-element values over time. The class' behavior is illustrated
+ * by this example:
+ * <pre>
+ *   // At 0 ms, the state of the tracked object is 0
+ *   counter.setState(0, 0);
+ *
+ *   // At 1000 ms, the state changes to 1
+ *   counter.setState(1, 1000);
+ *
+ *   // At 3000 ms, the tracked values are updated to {100, 200}
+ *   arrayContainer.setValues(new long[]{{30, 300}};
+ *   counter.updateValues(arrayContainer, 3000);
+ *
+ *   // The values are distributed between states 0 and 1 according to the time
+ *   // spent in those respective states. In this specific case, 1000 and 2000 ms.
+ *   counter.getValues(arrayContainer, 0);
+ *   // arrayContainer now has values {10, 100}
+ *   counter.getValues(arrayContainer, 1);
+ *   // arrayContainer now has values {20, 200}
+ * </pre>
+ *
+ * The tracked values are expected to increase monotonically.
+ *
+ * @hide
+ */
+public class LongArrayMultiStateCounter {
+
+    /**
+     * Container for a native equivalent of a long[].
+     */
+    public static class LongArrayContainer {
+        private static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                        LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
+
+        private final long mNativeObject;
+        private final int mLength;
+
+        public LongArrayContainer(int length) {
+            mLength = length;
+            mNativeObject = native_init(length);
+            sRegistry.registerNativeAllocation(this, mNativeObject);
+        }
+
+        /**
+         * Copies the supplied values into the underlying native array.
+         */
+        public void setValues(long[] array) {
+            if (array.length != mLength) {
+                throw new IllegalArgumentException(
+                        "Invalid array length: " + mLength + ", expected: " + mLength);
+            }
+            native_setValues(mNativeObject, array);
+        }
+
+        /**
+         * Copies the underlying native array values to the supplied array.
+         */
+        public void getValues(long[] array) {
+            if (array.length != mLength) {
+                throw new IllegalArgumentException(
+                        "Invalid array length: " + mLength + ", expected: " + mLength);
+            }
+            native_getValues(mNativeObject, array);
+        }
+
+        @CriticalNative
+        private static native long native_init(int length);
+
+        @CriticalNative
+        private static native long native_getReleaseFunc();
+
+        @FastNative
+        private native void native_setValues(long nativeObject, long[] array);
+
+        @FastNative
+        private native void native_getValues(long nativeObject, long[] array);
+    }
+
+    private static final NativeAllocationRegistry sRegistry =
+            NativeAllocationRegistry.createMalloced(
+                    LongArrayMultiStateCounter.class.getClassLoader(), native_getReleaseFunc());
+
+    private final int mStateCount;
+    private final int mLength;
+    private final long mNativeObject;
+
+    public LongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
+            long timestampMs) {
+        mStateCount = stateCount;
+        mLength = arrayLength;
+        mNativeObject = native_init(stateCount, arrayLength, initialState, timestampMs);
+        sRegistry.registerNativeAllocation(this, mNativeObject);
+    }
+
+    /**
+     * Sets the current state to the supplied value.
+     */
+    public void setState(int state, long timestampMs) {
+        if (state < 0 || state >= mStateCount) {
+            throw new IllegalArgumentException(
+                    "State: " + state + ", outside the range: [0-" + mStateCount + "]");
+        }
+        native_setState(mNativeObject, state, timestampMs);
+    }
+
+    /**
+     * Sets the new values.  The delta between the previously set values and these values
+     * is distributed among the state according to the time the object spent in those states
+     * since the previous call to updateValues.
+     */
+    public void updateValues(LongArrayContainer longArrayContainer, long timestampMs) {
+        if (longArrayContainer.mLength != mLength) {
+            throw new IllegalArgumentException(
+                    "Invalid array length: " + longArrayContainer.mLength + ", expected: "
+                            + mLength);
+        }
+        native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
+    }
+
+    /**
+     * Populates longArrayContainer with the accumulated counts for the specified state.
+     */
+    public void getCounts(LongArrayContainer longArrayContainer, int state) {
+        if (state < 0 || state >= mStateCount) {
+            throw new IllegalArgumentException(
+                    "State: " + state + ", outside the range: [0-" + mStateCount + "]");
+        }
+        native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state);
+    }
+
+    @Override
+    public String toString() {
+        return native_toString(mNativeObject);
+    }
+
+    @CriticalNative
+    private static native long native_init(int stateCount, int arrayLength, int initialState,
+            long timestampMs);
+
+    @CriticalNative
+    private static native long native_getReleaseFunc();
+
+    @CriticalNative
+    private static native void native_setState(long nativeObject, int state, long timestampMs);
+
+    @CriticalNative
+    private static native void native_updateValues(long nativeObject,
+            long longArrayContainerNativeObject, long timestampMs);
+
+    @CriticalNative
+    private static native void native_getCounts(long nativeObject,
+            long longArrayContainerNativeObject, int state);
+
+    @FastNative
+    private native String native_toString(long nativeObject);
+}
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index b4a2b63..c527c06 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -175,8 +175,11 @@
         final double systemUidModeledPowerMah = mCpuPowerCalculator.calculateUidModeledPowerMah(
                 systemUid, BatteryStats.STATS_SINCE_CHARGED);
 
-        return uCtoMah(consumptionUC) * systemServiceModeledPowerMah
-                / systemUidModeledPowerMah;
+        if (systemUidModeledPowerMah > 0) {
+            return uCtoMah(consumptionUC) * systemServiceModeledPowerMah / systemUidModeledPowerMah;
+        } else {
+            return 0;
+        }
     }
 
     private double calculatePowerUsingPowerProfile(BatteryStats batteryStats) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 0f26f57e..29e5a5a 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -33,13 +33,11 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.ZygoteProcess;
-import android.os.storage.StorageManager;
 import android.provider.DeviceConfig;
 import android.security.keystore2.AndroidKeyStoreProvider;
 import android.system.ErrnoException;
@@ -58,7 +56,6 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.Preconditions;
 
-import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
 import dalvik.system.ZygoteHooks;
 
@@ -514,7 +511,6 @@
 
         final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
         if (systemServerClasspath != null) {
-            performSystemServerDexOpt(systemServerClasspath);
             // Capturing profiles is only supported for debug or eng builds since selinux normally
             // prevents it.
             if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
@@ -656,95 +652,6 @@
     }
 
     /**
-     * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
-     * set of the current runtime.
-     */
-    private static void performSystemServerDexOpt(String classPath) {
-        final String[] classPathElements = classPath.split(":");
-        final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
-
-        String classPathForElement = "";
-        for (String classPathElement : classPathElements) {
-            // We default to the verify filter because the compilation will happen on /data and
-            // system server cannot load executable code outside /system.
-            String systemServerFilter = SystemProperties.get(
-                    "dalvik.vm.systemservercompilerfilter", "verify");
-
-            String classLoaderContext =
-                        getSystemServerClassLoaderContext(classPathForElement);
-            int dexoptNeeded;
-            try {
-                dexoptNeeded = DexFile.getDexOptNeeded(
-                        classPathElement, instructionSet, systemServerFilter,
-                        classLoaderContext, false /* newProfile */, false /* downgrade */);
-            } catch (FileNotFoundException ignored) {
-                // Do not add to the classpath.
-                Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
-                continue;
-            } catch (IOException e) {
-                // Not fully clear what to do here as we don't know the cause of the
-                // IO exception. Add to the classpath to be conservative, but don't
-                // attempt to compile it.
-                Log.w(TAG, "Error checking classpath element for system server: "
-                        + classPathElement, e);
-                dexoptNeeded = DexFile.NO_DEXOPT_NEEDED;
-            }
-
-            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                final String packageName = "*";
-                final String outputPath = null;
-                final int dexFlags = 0;
-                final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
-                final String seInfo = null;
-                final int targetSdkVersion = 0;  // SystemServer targets the system's SDK version
-                // Wait for installd to be made available
-                IInstalld installd = IInstalld.Stub.asInterface(
-                        ServiceManager.waitForService("installd"));
-
-                try {
-                    installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
-                            instructionSet, dexoptNeeded, outputPath, dexFlags, systemServerFilter,
-                            uuid, classLoaderContext, seInfo, false /* downgrade */,
-                            targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
-                            "server-dexopt");
-                } catch (RemoteException | ServiceSpecificException e) {
-                    // Ignore (but log), we need this on the classpath for fallback mode.
-                    Log.w(TAG, "Failed compiling classpath element for system server: "
-                            + classPathElement, e);
-                }
-            }
-
-            classPathForElement = encodeSystemServerClassPath(
-                    classPathForElement, classPathElement);
-        }
-    }
-
-    /**
-     * Encodes the system server class loader context in a format that is accepted by dexopt. This
-     * assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
-     *
-     * Note that ideally we would use the {@code DexoptUtils} to compute this. However we have no
-     * dependency here on the server so we hard code the logic again.
-     */
-    private static String getSystemServerClassLoaderContext(String classPath) {
-        return classPath == null ? "PCL[]" : "PCL[" + classPath + "]";
-    }
-
-    /**
-     * Encodes the class path in a format accepted by dexopt.
-     *
-     * @param classPath  The old class path (may be empty).
-     * @param newElement  The new class path elements
-     * @return The class path encoding resulted from appending {@code newElement} to {@code
-     * classPath}.
-     */
-    private static String encodeSystemServerClassPath(String classPath, String newElement) {
-        return (classPath == null || classPath.isEmpty())
-                ? newElement
-                : classPath + ":" + newElement;
-    }
-
-    /**
      * Prepare the arguments and forks for the system server process.
      *
      * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index 52172cf..ec62839 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -16,7 +16,9 @@
 
 package com.android.internal.policy;
 
+import android.content.Context;
 import android.content.res.Resources;
+import android.view.RoundedCorners;
 
 import com.android.internal.R;
 
@@ -29,23 +31,28 @@
      * Corner radius that should be used on windows in order to cover the display.
      * These values are expressed in pixels because they should not respect display or font
      * scaling, this means that we don't have to reload them on config changes.
+     *
+     * Note that if the context is not an UI context(not associated with Display), it will use
+     * default display.
      */
-    public static float getWindowCornerRadius(Resources resources) {
+    public static float getWindowCornerRadius(Context context) {
+        final Resources resources = context.getResources();
         if (!supportsRoundedCornersOnWindows(resources)) {
             return 0f;
         }
-
+        // Use Context#getDisplayNoVerify() in case the context is not an UI context.
+        final String displayUniqueId = context.getDisplayNoVerify().getUniqueId();
         // Radius that should be used in case top or bottom aren't defined.
-        float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius)
-                - resources.getDimension(R.dimen.rounded_corner_radius_adjustment);
+        float defaultRadius = RoundedCorners.getRoundedCornerRadius(resources, displayUniqueId)
+                - RoundedCorners.getRoundedCornerRadiusAdjustment(resources, displayUniqueId);
 
-        float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top)
-                - resources.getDimension(R.dimen.rounded_corner_radius_top_adjustment);
+        float topRadius = RoundedCorners.getRoundedCornerTopRadius(resources, displayUniqueId)
+                - RoundedCorners.getRoundedCornerRadiusTopAdjustment(resources, displayUniqueId);
         if (topRadius == 0f) {
             topRadius = defaultRadius;
         }
-        float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom)
-                - resources.getDimension(R.dimen.rounded_corner_radius_bottom_adjustment);
+        float bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(resources, displayUniqueId)
+                - RoundedCorners.getRoundedCornerRadiusBottomAdjustment(resources, displayUniqueId);
         if (bottomRadius == 0f) {
             bottomRadius = defaultRadius;
         }
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index ce3efd3..db019a67 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -80,6 +80,10 @@
             Consts.TAG_WM),
     WM_DEBUG_WINDOW_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM),
+    WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+            Consts.TAG_WM),
     TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
 
     private final boolean mEnabled;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 84a7f2f..b427e8b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -149,7 +149,7 @@
     */
     void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
             in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
-            String opPackageName, long operationId, int multiSensorConfig);
+            long operationId, String opPackageName, long requestId, int multiSensorConfig);
     /**
     * Used to notify the authentication dialog that a biometric has been authenticated.
     */
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index e7d6d6c..b3499db 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -110,7 +110,8 @@
     // Used to show the authentication dialog (Biometrics, Device Credential)
     void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
             in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
-            int userId, String opPackageName, long operationId, int multiSensorConfig);
+            int userId, long operationId, String opPackageName, long requestId,
+            int multiSensorConfig);
 
     // Used to notify the authentication dialog that a biometric has been authenticated
     void onBiometricAuthenticated();
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index f3d0858..4b1753a 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -63,6 +63,7 @@
     void onActiveDataSubIdChanged(in int subId);
     void onRadioPowerStateChanged(in int state);
     void onCallAttributesChanged(in CallAttributes callAttributes);
+    @SuppressWarnings(value={"untyped-collection"})
     void onEmergencyNumberListChanged(in Map emergencyNumberList);
     void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
     void onOutgoingEmergencySms(in EmergencyNumber sentEmergencyNumber, int subscriptionId);
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index c6fd6ee..9bdcddf 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -891,4 +891,18 @@
     public static @Nullable <T> T firstOrNull(T[] items) {
         return items.length > 0 ? items[0] : null;
     }
+
+    /**
+     * Creates a {@link List} from an array. Different from {@link Arrays#asList(Object[])} as that
+     * will use the parameter as the backing array, meaning changes are not isolated.
+     */
+    public static <T> List<T> toList(T[] array) {
+        List<T> list = new ArrayList<>(array.length);
+        //noinspection ManualArrayToCollectionCopy
+        for (T item : array) {
+            //noinspection UseBulkOperation
+            list.add(item);
+        }
+        return list;
+    }
 }
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index c6a040c..b87027c 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -227,6 +227,13 @@
     }
 
     /**
+     * Returns whether the given map {@link Map#isEmpty is empty} or {@code null}
+     */
+    public static boolean isEmpty(@Nullable Map<?, ?> cur) {
+        return size(cur) == 0;
+    }
+
+    /**
      * Returns the elements of the given list that are of type {@code c}
      */
     public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) {
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 8b3c133..7a712e5 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -291,10 +291,10 @@
      * Finds a suitable color such that there's enough contrast.
      *
      * @param color the color to start searching from.
-     * @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
-     * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
+     * @param other the color to ensure contrast against. Assumed to be lighter than {@code color}
+     * @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
      * @param minRatio the minimum contrast ratio required.
-     * @return a color with the same hue as {@param color}, potentially darkened to meet the
+     * @return a color with the same hue as {@code color}, potentially darkened to meet the
      *          contrast ratio.
      */
     public static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
@@ -331,7 +331,7 @@
      * @param color the color to start searching from.
      * @param backgroundColor the color to ensure contrast against.
      * @param minRatio the minimum contrast ratio required.
-     * @return the same color as {@param color} with potentially modified alpha to meet contrast
+     * @return the same color as {@code color} with potentially modified alpha to meet contrast
      */
     public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
         int fg = color;
@@ -361,10 +361,10 @@
      * Finds a suitable color such that there's enough contrast.
      *
      * @param color the color to start searching from.
-     * @param other the color to ensure contrast against. Assumed to be darker than {@param color}
-     * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
+     * @param other the color to ensure contrast against. Assumed to be darker than {@code color}
+     * @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
      * @param minRatio the minimum contrast ratio required.
-     * @return a color with the same hue as {@param color}, potentially darkened to meet the
+     * @return a color with the same hue as {@code color}, potentially lightened to meet the
      *          contrast ratio.
      */
     public static int findContrastColorAgainstDark(int color, int other, boolean findFg,
@@ -393,7 +393,8 @@
                 low = l;
             }
         }
-        return findFg ? fg : bg;
+        hsl[2] = high;
+        return ColorUtilsFromCompat.HSLToColor(hsl);
     }
 
     public static int ensureTextContrastOnBlack(int color) {
@@ -452,7 +453,7 @@
     }
 
     /**
-     * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
+     * Resolves {@code color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
      */
     public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
         if (color == Notification.COLOR_DEFAULT) {
diff --git a/core/java/com/android/internal/util/IState.java b/core/java/com/android/internal/util/IState.java
index 07837bf..41b3d5e 100644
--- a/core/java/com/android/internal/util/IState.java
+++ b/core/java/com/android/internal/util/IState.java
@@ -27,12 +27,12 @@
 public interface IState {
 
     /**
-     * Returned by processMessage to indicate the the message was processed.
+     * Returned by processMessage to indicate the message was processed.
      */
     static final boolean HANDLED = true;
 
     /**
-     * Returned by processMessage to indicate the the message was NOT processed.
+     * Returned by processMessage to indicate the message was NOT processed.
      */
     static final boolean NOT_HANDLED = false;
 
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 5b68159..100a605d 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -1,6 +1,7 @@
 per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com
 per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
 per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
 per-file Protocol* = etancohen@google.com, lorenzo@google.com
 per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
 per-file DataClass* = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 4cff785..cb8d9d1 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -48,7 +48,7 @@
  * in Object Oriented programming and are used to perform initialization and
  * cleanup of the state respectively. The <code>getName</code> method returns the
  * name of the state; the default implementation returns the class name. It may be
- * desirable to have <code>getName</code> return the the state instance name instead,
+ * desirable to have <code>getName</code> return the state instance name instead,
  * in particular if a particular state class has multiple instances.</p>
  *
  * <p>When a state machine is created, <code>addState</code> is used to build the
@@ -433,14 +433,14 @@
 
     /**
      * Convenience constant that maybe returned by processMessage
-     * to indicate the the message was processed and is not to be
+     * to indicate the message was processed and is not to be
      * processed by parent states
      */
     public static final boolean HANDLED = true;
 
     /**
      * Convenience constant that maybe returned by processMessage
-     * to indicate the the message was NOT processed and is to be
+     * to indicate the message was NOT processed and is to be
      * processed by parent states
      */
     public static final boolean NOT_HANDLED = false;
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index dd42c40e..12a98c1 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -23,11 +23,7 @@
 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;
+import com.android.internal.infra.AndroidFuture;
 
 /**
  * Interface from an input method to the application, allowing it to perform
@@ -35,14 +31,14 @@
  * {@hide}
  */
  oneway interface IInputContext {
-    void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback);
+    void getTextBeforeCursor(int length, int flags, in AndroidFuture future /* T=CharSequence */);
 
-    void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback);
+    void getTextAfterCursor(int length, int flags, in AndroidFuture future /* T=CharSequence */);
 
-    void getCursorCapsMode(int reqModes, IIntResultCallback callback);
+    void getCursorCapsMode(int reqModes, in AndroidFuture future /* T=Integer */);
 
     void getExtractedText(in ExtractedTextRequest request, int flags,
-            IExtractedTextResultCallback callback);
+            in AndroidFuture future /* T=ExtractedText */);
 
     void deleteSurroundingText(int beforeLength, int afterLength);
     void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
@@ -50,7 +46,7 @@
     void setComposingText(CharSequence text, int newCursorPosition);
 
     void finishComposingText();
-    
+
     void commitText(CharSequence text, int newCursorPosition);
 
     void commitCompletion(in CompletionInfo completion);
@@ -58,34 +54,34 @@
     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 getSelectedText(int flags, in AndroidFuture future /* T=CharSequence */);
 
-    void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback);
+    void requestCursorUpdates(int cursorUpdateMode, in AndroidFuture future /* T=Boolean */);
 
     void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts,
-            IBooleanResultCallback callback);
+            in AndroidFuture future /* T=Boolean */);
 
     void getSurroundingText(int beforeLength, int afterLength, int flags,
-            ISurroundingTextResultCallback callback);
+            in AndroidFuture future /* T=SurroundingText */);
 
     void setImeConsumesInput(boolean imeConsumesInput);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 498505c..dbf4528 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -846,14 +846,6 @@
         return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
     }
 
-    /**
-     * Retrieves whether the current DPM allows use of the Profile Challenge.
-     */
-    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
-        return isManagedProfile(userHandle)
-                && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
-    }
-
     private boolean hasSeparateChallenge(int userHandle) {
         try {
             return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 3f756d7..3994fbd 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -18,17 +18,22 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.os.Bundle;
@@ -52,6 +57,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.R;
+import com.android.internal.graphics.ColorUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -70,7 +76,12 @@
     private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
 
     private static final boolean PROFILE_DRAWING = false;
-    private static final float LINE_FADE_ALPHA_MULTIPLIER = 1.5f;
+    private static final int LINE_END_ANIMATION_DURATION_MILLIS = 50;
+    private static final int LINE_FADE_OUT_DURATION_MILLIS = 500;
+    private static final int LINE_FADE_OUT_DELAY_MILLIS = 150;
+    private static final int DOT_ACTIVATION_DURATION_MILLIS = 50;
+    private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96;
+    private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192;
     private final CellState[][] mCellStates;
 
     private final int mDotSize;
@@ -139,6 +150,7 @@
     private float mSquareWidth;
     @UnsupportedAppUsage
     private float mSquareHeight;
+    private final LinearGradient mFadeOutGradientShader;
 
     private final Path mCurrentPath = new Path();
     private final Rect mInvalidate = new Rect();
@@ -149,6 +161,7 @@
     private int mErrorColor;
     private int mSuccessColor;
     private int mDotColor;
+    private int mDotActivatedColor;
 
     private final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mLinearOutSlowInInterpolator;
@@ -230,9 +243,11 @@
         float radius;
         float translationY;
         float alpha = 1f;
+        float activationAnimationProgress;
         public float lineEndX = Float.MIN_VALUE;
         public float lineEndY = Float.MIN_VALUE;
-        public ValueAnimator lineAnimator;
+        @Nullable
+        Animator activationAnimator;
      }
 
     /**
@@ -320,6 +335,7 @@
         mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, 0);
         mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, 0);
         mDotColor = a.getColor(R.styleable.LockPatternView_dotColor, mRegularColor);
+        mDotActivatedColor = a.getColor(R.styleable.LockPatternView_dotActivatedColor, mDotColor);
 
         int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor);
         mPathPaint.setColor(pathColor);
@@ -361,6 +377,14 @@
         mExploreByTouchHelper = new PatternExploreByTouchHelper(this);
         setAccessibilityDelegate(mExploreByTouchHelper);
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+
+        int fadeAwayGradientWidth = getResources().getDimensionPixelSize(
+                R.dimen.lock_pattern_fade_away_gradient_width);
+        // Set up gradient shader with the middle in point (0, 0).
+        mFadeOutGradientShader = new LinearGradient(/* x0= */ -fadeAwayGradientWidth / 2f,
+                /* y0= */ 0,/* x1= */ fadeAwayGradientWidth / 2f, /* y1= */ 0,
+                Color.TRANSPARENT, pathColor, Shader.TileMode.CLAMP);
+
         a.recycle();
     }
 
@@ -780,64 +804,111 @@
 
     private void startCellActivatedAnimation(Cell cell) {
         final CellState cellState = mCellStates[cell.row][cell.column];
-        startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator,
-                cellState, new Runnable() {
-                    @Override
-                    public void run() {
-                        startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192,
-                                mFastOutSlowInInterpolator,
-                                cellState, null);
-                    }
-                });
-        startLineEndAnimation(cellState, mInProgressX, mInProgressY,
-                getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
-    }
 
-    private void startLineEndAnimation(final CellState state,
-            final float startX, final float startY, final float targetX, final float targetY) {
-        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
-        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (float) animation.getAnimatedValue();
-                state.lineEndX = (1 - t) * startX + t * targetX;
-                state.lineEndY = (1 - t) * startY + t * targetY;
-                invalidate();
-            }
-        });
-        valueAnimator.addListener(new AnimatorListenerAdapter() {
+        if (cellState.activationAnimator != null) {
+            cellState.activationAnimator.cancel();
+        }
+        AnimatorSet animatorSet = new AnimatorSet();
+        AnimatorSet.Builder animatorSetBuilder = animatorSet
+                .play(createLineDisappearingAnimation())
+                .with(createLineEndAnimation(cellState, mInProgressX, mInProgressY,
+                        getCenterXForColumn(cell.column), getCenterYForRow(cell.row)));
+        if (mDotSize != mDotSizeActivated) {
+            animatorSetBuilder.with(createDotRadiusAnimation(cellState));
+        }
+        if (mDotColor != mDotActivatedColor) {
+            animatorSetBuilder.with(createDotActivationColorAnimation(cellState));
+        }
+
+        animatorSet.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                state.lineAnimator = null;
-            }
-        });
-        valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
-        valueAnimator.setDuration(100);
-        valueAnimator.start();
-        state.lineAnimator = valueAnimator;
-    }
-
-    private void startRadiusAnimation(float start, float end, long duration,
-            Interpolator interpolator, final CellState state, final Runnable endRunnable) {
-        ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
-        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                state.radius = (float) animation.getAnimatedValue();
+                cellState.activationAnimator = null;
                 invalidate();
             }
         });
-        if (endRunnable != null) {
-            valueAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    endRunnable.run();
-                }
-            });
-        }
-        valueAnimator.setInterpolator(interpolator);
-        valueAnimator.setDuration(duration);
-        valueAnimator.start();
+        cellState.activationAnimator = animatorSet;
+        animatorSet.start();
+    }
+
+    private Animator createDotActivationColorAnimation(CellState cellState) {
+        ValueAnimator.AnimatorUpdateListener updateListener =
+                valueAnimator -> {
+                    cellState.activationAnimationProgress =
+                            (float) valueAnimator.getAnimatedValue();
+                    invalidate();
+                };
+        ValueAnimator activateAnimator = ValueAnimator.ofFloat(0f, 1f);
+        ValueAnimator deactivateAnimator = ValueAnimator.ofFloat(1f, 0f);
+        activateAnimator.addUpdateListener(updateListener);
+        deactivateAnimator.addUpdateListener(updateListener);
+        activateAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        deactivateAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+
+        // Align dot animation duration with line fade out animation.
+        activateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
+        deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
+        AnimatorSet set = new AnimatorSet();
+        set.play(deactivateAnimator)
+                .after(LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS
+                        - DOT_ACTIVATION_DURATION_MILLIS * 2)
+                .after(activateAnimator);
+        return set;
+    }
+
+    /**
+     * On the last frame before cell activates the end point of in progress line is not aligned
+     * with dot center so we execute a short animation moving the end point to exact dot center.
+     */
+    private Animator createLineEndAnimation(final CellState state,
+            final float startX, final float startY, final float targetX, final float targetY) {
+        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
+        valueAnimator.addUpdateListener(animation -> {
+            float t = (float) animation.getAnimatedValue();
+            state.lineEndX = (1 - t) * startX + t * targetX;
+            state.lineEndY = (1 - t) * startY + t * targetY;
+            invalidate();
+        });
+        valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        valueAnimator.setDuration(LINE_END_ANIMATION_DURATION_MILLIS);
+        return valueAnimator;
+    }
+
+    /**
+     * Starts animator to fade out a line segment. It does only invalidate because all the
+     * transitions are applied in {@code onDraw} method.
+     */
+    private Animator createLineDisappearingAnimation() {
+        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
+        valueAnimator.addUpdateListener(animation -> invalidate());
+        valueAnimator.setStartDelay(LINE_FADE_OUT_DELAY_MILLIS);
+        valueAnimator.setDuration(LINE_FADE_OUT_DURATION_MILLIS);
+        return valueAnimator;
+    }
+
+    private Animator createDotRadiusAnimation(CellState state) {
+        float defaultRadius = mDotSize / 2f;
+        float activatedRadius = mDotSizeActivated / 2f;
+
+        ValueAnimator.AnimatorUpdateListener animatorUpdateListener =
+                animation -> {
+                    state.radius = (float) animation.getAnimatedValue();
+                    invalidate();
+                };
+
+        ValueAnimator activationAnimator = ValueAnimator.ofFloat(defaultRadius, activatedRadius);
+        activationAnimator.addUpdateListener(animatorUpdateListener);
+        activationAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+        activationAnimator.setDuration(DOT_RADIUS_INCREASE_DURATION_MILLIS);
+
+        ValueAnimator deactivationAnimator = ValueAnimator.ofFloat(activatedRadius, defaultRadius);
+        deactivationAnimator.addUpdateListener(animatorUpdateListener);
+        deactivationAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        deactivationAnimator.setDuration(DOT_RADIUS_DECREASE_DURATION_MILLIS);
+
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(activationAnimator, deactivationAnimator);
+        return set;
     }
 
     // helper method to find which cell a point maps to
@@ -1051,8 +1122,11 @@
         for (int i = 0; i < 3; i++) {
             for (int j = 0; j < 3; j++) {
                 CellState state = mCellStates[i][j];
-                if (state.lineAnimator != null) {
-                    state.lineAnimator.cancel();
+                if (state.activationAnimator != null) {
+                    state.activationAnimator.cancel();
+                    state.activationAnimator = null;
+                    state.radius = mDotSize / 2f;
+                    state.activationAnimationProgress = 0f;
                     state.lineEndX = Float.MIN_VALUE;
                     state.lineEndY = Float.MIN_VALUE;
                 }
@@ -1195,29 +1269,19 @@
                 float centerX = getCenterXForColumn(cell.column);
                 float centerY = getCenterYForRow(cell.row);
                 if (i != 0) {
-                   // Set this line segment to fade away animated.
-                   int lineFadeVal = (int) Math.min((elapsedRealtime -
-                           mLineFadeStart[i]) * LINE_FADE_ALPHA_MULTIPLIER, 255f);
-
                     CellState state = mCellStates[cell.row][cell.column];
                     currentPath.rewind();
-                    currentPath.moveTo(lastX, lastY);
+                    float endX;
+                    float endY;
                     if (state.lineEndX != Float.MIN_VALUE && state.lineEndY != Float.MIN_VALUE) {
-                        currentPath.lineTo(state.lineEndX, state.lineEndY);
-                        if (mFadePattern) {
-                            mPathPaint.setAlpha((int) 255 - lineFadeVal );
-                        } else {
-                            mPathPaint.setAlpha(255);
-                        }
+                        endX = state.lineEndX;
+                        endY = state.lineEndY;
                     } else {
-                        currentPath.lineTo(centerX, centerY);
-                        if (mFadePattern) {
-                            mPathPaint.setAlpha((int) 255 - lineFadeVal );
-                        } else {
-                            mPathPaint.setAlpha(255);
-                        }
+                        endX = centerX;
+                        endY = centerY;
                     }
-                    canvas.drawPath(currentPath, mPathPaint);
+                    drawLineSegment(canvas, /* startX = */ lastX, /* startY = */ lastY, endX, endY,
+                            mLineFadeStart[i], elapsedRealtime);
                 }
                 lastX = centerX;
                 lastY = centerY;
@@ -1253,13 +1317,69 @@
                                 cellState.hwRadius, cellState.hwPaint);
                     } else {
                         drawCircle(canvas, (int) centerX, (int) centerY + translationY,
-                                cellState.radius, drawLookup[i][j], cellState.alpha);
+                                cellState.radius, drawLookup[i][j], cellState.alpha,
+                                cellState.activationAnimationProgress);
                     }
                 }
             }
         }
     }
 
+    private void drawLineSegment(Canvas canvas, float startX, float startY, float endX, float endY,
+            long lineFadeStart, long elapsedRealtime) {
+        float fadeAwayProgress;
+        if (mFadePattern) {
+            if (elapsedRealtime - lineFadeStart
+                    >= LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS) {
+                // Time for this segment animation is out so we don't need to draw it.
+                return;
+            }
+            // Set this line segment to fade away animated.
+            fadeAwayProgress = Math.max(
+                    ((float) (elapsedRealtime - lineFadeStart - LINE_FADE_OUT_DELAY_MILLIS))
+                            / LINE_FADE_OUT_DURATION_MILLIS, 0f);
+            drawFadingAwayLineSegment(canvas, startX, startY, endX, endY, fadeAwayProgress);
+        } else {
+            mPathPaint.setAlpha(255);
+            canvas.drawLine(startX, startY, endX, endY, mPathPaint);
+        }
+    }
+
+    private void drawFadingAwayLineSegment(Canvas canvas, float startX, float startY, float endX,
+            float endY, float fadeAwayProgress) {
+        mPathPaint.setAlpha((int) (255 * (1 - fadeAwayProgress)));
+
+        // To draw gradient segment we use mFadeOutGradientShader which has immutable coordinates
+        // thus we will need to translate and rotate the canvas.
+        mPathPaint.setShader(mFadeOutGradientShader);
+        canvas.save();
+
+        // First translate canvas to gradient middle point.
+        float gradientMidX = endX * fadeAwayProgress + startX * (1 - fadeAwayProgress);
+        float gradientMidY = endY * fadeAwayProgress + startY * (1 - fadeAwayProgress);
+        canvas.translate(gradientMidX, gradientMidY);
+
+        // Then rotate it to the direction of the segment.
+        double segmentAngleRad = Math.atan((endY - startY) / (endX - startX));
+        float segmentAngleDegrees = (float) Math.toDegrees(segmentAngleRad);
+        if (endX - startX < 0) {
+            // Arc tangent gives us angle degrees [-90; 90] thus to cover [90; 270] degrees we
+            // need this hack.
+            segmentAngleDegrees += 180f;
+        }
+        canvas.rotate(segmentAngleDegrees);
+
+        // Pythagoras theorem.
+        float segmentLength = (float) Math.hypot(endX - startX, endY - startY);
+
+        // Draw the segment in coordinates aligned with shader coordinates.
+        canvas.drawLine(/* startX= */ -segmentLength * fadeAwayProgress, /* startY= */
+                0,/* stopX= */ segmentLength * (1 - fadeAwayProgress), /* stopY= */ 0, mPathPaint);
+
+        canvas.restore();
+        mPathPaint.setShader(null);
+    }
+
     private float calculateLastSegmentAlpha(float x, float y, float lastX, float lastY) {
         float diffX = x - lastX;
         float diffY = y - lastY;
@@ -1298,8 +1418,14 @@
      * @param partOfPattern Whether this circle is part of the pattern.
      */
     private void drawCircle(Canvas canvas, float centerX, float centerY, float radius,
-            boolean partOfPattern, float alpha) {
-        mPaint.setColor(getDotColor());
+            boolean partOfPattern, float alpha, float activationAnimationProgress) {
+        if (mFadePattern && !mInStealthMode) {
+            int resultColor = ColorUtils.blendARGB(mDotColor, mDotActivatedColor,
+                    /* ratio= */ activationAnimationProgress);
+            mPaint.setColor(resultColor);
+        } else {
+            mPaint.setColor(getDotColor());
+        }
         mPaint.setAlpha((int) (alpha * 255));
         canvas.drawCircle(centerX, centerY, radius, mPaint);
     }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 4fc135c..627381c 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -66,15 +66,15 @@
         private float[] mTraceY = new float[32];
         private boolean[] mTraceCurrent = new boolean[32];
         private int mTraceCount;
-        
+
         // True if the pointer is down.
         @UnsupportedAppUsage
         private boolean mCurDown;
-        
+
         // Most recent coordinates.
         private PointerCoords mCoords = new PointerCoords();
         private int mToolType;
-        
+
         // Most recent velocity.
         private float mXVelocity;
         private float mYVelocity;
@@ -107,7 +107,7 @@
                 float[] newTraceX = new float[traceCapacity];
                 System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount);
                 mTraceX = newTraceX;
-                
+
                 float[] newTraceY = new float[traceCapacity];
                 System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount);
                 mTraceY = newTraceY;
@@ -116,7 +116,7 @@
                 System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount);
                 mTraceCurrent= newTraceCurrent;
             }
-            
+
             mTraceX[mTraceCount] = x;
             mTraceY[mTraceCount] = y;
             mTraceCurrent[mTraceCount] = current;
@@ -162,7 +162,7 @@
 
     @UnsupportedAppUsage
     private boolean mPrintCoords = true;
-    
+
     public PointerLocationView(Context c) {
         super(c);
         setFocusableInTouchMode(true);
@@ -211,7 +211,7 @@
         PointerState ps = new PointerState();
         mPointers.add(ps);
         mActivePointerId = 0;
-        
+
         mVelocity = VelocityTracker.obtain();
 
         String altStrategy = SystemProperties.get(ALT_STRATEGY_PROPERY_KEY);
@@ -252,7 +252,7 @@
                     + " bottom=" + mTextMetrics.bottom);
         }
     }
-    
+
     // Draw an oval.  When angle is 0 radians, orients the major axis vertically,
     // angles less than or greater than 0 radians rotate the major axis left or right.
     private RectF mReusableOvalRect = new RectF();
@@ -399,7 +399,7 @@
     }
 
     private void drawLabels(Canvas canvas) {
-        if (mActivePointerId < 0) {
+        if (mActivePointerId < 0 || mActivePointerId >= mPointers.size()) {
             return;
         }
 
@@ -614,8 +614,8 @@
                 NP++;
             }
 
-            if (mActivePointerId < 0 ||
-                    !mPointers.get(mActivePointerId).mCurDown) {
+            if (mActivePointerId < 0 || mActivePointerId >= NP
+                    || !mPointers.get(mActivePointerId).mCurDown) {
                 mActivePointerId = id;
             }
 
@@ -710,7 +710,7 @@
 
         invalidate();
     }
-    
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         onPointerEvent(event);
@@ -862,16 +862,16 @@
     private static final class FasterStringBuilder {
         private char[] mChars;
         private int mLength;
-        
+
         public FasterStringBuilder() {
             mChars = new char[64];
         }
-        
+
         public FasterStringBuilder clear() {
             mLength = 0;
             return this;
         }
-        
+
         public FasterStringBuilder append(String value) {
             final int valueLength = value.length();
             final int index = reserve(valueLength);
@@ -879,11 +879,11 @@
             mLength += valueLength;
             return this;
         }
-        
+
         public FasterStringBuilder append(int value) {
             return append(value, 0);
         }
-        
+
         public FasterStringBuilder append(int value, int zeroPadWidth) {
             final boolean negative = value < 0;
             if (negative) {
@@ -893,16 +893,16 @@
                     return this;
                 }
             }
-            
+
             int index = reserve(11);
             final char[] chars = mChars;
-            
+
             if (value == 0) {
                 chars[index++] = '0';
                 mLength += 1;
                 return this;
             }
-            
+
             if (negative) {
                 chars[index++] = '-';
             }
@@ -916,18 +916,18 @@
                     chars[index++] = '0';
                 }
             }
-            
+
             do {
                 int digit = value / divisor;
                 value -= digit * divisor;
                 divisor /= 10;
                 chars[index++] = (char) (digit + '0');
             } while (divisor != 0);
-            
+
             mLength = index;
             return this;
         }
-        
+
         public FasterStringBuilder append(float value, int precision) {
             int scale = 1;
             for (int i = 0; i < precision; i++) {
@@ -947,15 +947,15 @@
                 value -= Math.floor(value);
                 append((int) (value * scale), precision);
             }
-            
+
             return this;
         }
-        
+
         @Override
         public String toString() {
             return new String(mChars, 0, mLength);
         }
-        
+
         private int reserve(int length) {
             final int oldLength = mLength;
             final int newLength = mLength + length;
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 6cbace4..b0cf5dc 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -573,13 +573,14 @@
         if (!isSystemProcess()) {
             return;
         }
-        // Read configuration of libs from apex module.
+        // Read configuration of features and libs from apex module.
+        int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES;
         // TODO: Use a solid way to filter apex module folders?
         for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
             if (f.isFile() || f.getPath().contains("@")) {
                 continue;
             }
-            readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);
+            readPermissions(Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag);
         }
     }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e9e2fff..21a327c 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -162,6 +162,7 @@
                 "android_util_CharsetUtils.cpp",
                 "android_util_MemoryIntArray.cpp",
                 "android_util_Process.cpp",
+                "android_media_audio_common_AidlConversion.cpp",
                 "android_media_AudioDeviceAttributes.cpp",
                 "android_media_AudioEffectDescriptor.cpp",
                 "android_media_AudioRecord.cpp",
@@ -216,6 +217,7 @@
                 "com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
                 "com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp",
                 "com_android_internal_os_KernelSingleUidTimeReader.cpp",
+                "com_android_internal_os_LongArrayMultiStateCounter.cpp",
                 "com_android_internal_os_Zygote.cpp",
                 "com_android_internal_os_ZygoteCommandBuffer.cpp",
                 "com_android_internal_os_ZygoteInit.cpp",
@@ -224,6 +226,7 @@
                 "fd_utils.cpp",
                 "android_hardware_input_InputWindowHandle.cpp",
                 "android_hardware_input_InputApplicationHandle.cpp",
+                "android_window_WindowInfosListener.cpp",
             ],
 
             static_libs: [
@@ -236,14 +239,19 @@
                 "libgrallocusage",
                 "libscrypt_static",
                 "libstatssocket_lazy",
+                "libskia",
             ],
 
             shared_libs: [
+                "android.media.audio.common.types-V1-cpp",
                 "audioclient-types-aidl-cpp",
                 "audioflinger-aidl-cpp",
+                "audiopolicy-types-aidl-cpp",
+                "spatializer-aidl-cpp",
                 "av-types-aidl-cpp",
                 "android.hardware.camera.device@3.2",
                 "libandroidicu",
+                "libbattery",
                 "libbpf_android",
                 "libnetdbpf",
                 "libnetdutils",
@@ -282,6 +290,7 @@
                 "libmediametrics",
                 "libmeminfo",
                 "libaudioclient",
+                "libaudioclient_aidl_conversion",
                 "libaudiofoundation",
                 "libaudiopolicy",
                 "libusbhost",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 97cac29..91179c2 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -98,6 +98,7 @@
 extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env);
 extern int register_android_media_MicrophoneInfo(JNIEnv *env);
 extern int register_android_media_ToneGenerator(JNIEnv *env);
+extern int register_android_media_audio_common_AidlConversion(JNIEnv* env);
 extern int register_android_media_midi(JNIEnv *env);
 
 namespace android {
@@ -203,11 +204,13 @@
 extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
 extern int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv* env);
 extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
+extern int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv* env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
 extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
 extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
 extern int register_com_android_internal_security_VerityUtils(JNIEnv* env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
+extern int register_android_window_WindowInfosListener(JNIEnv* env);
 
 // Namespace for Android Runtime flags applied during boot time.
 static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
@@ -1584,6 +1587,7 @@
         REG_JNI(register_com_android_internal_content_om_OverlayConfig),
         REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
         REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
+        REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),
         REG_JNI(register_com_android_internal_os_Zygote),
         REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
         REG_JNI(register_com_android_internal_os_ZygoteInit),
@@ -1615,6 +1619,7 @@
         REG_JNI(register_android_media_MicrophoneInfo),
         REG_JNI(register_android_media_RemoteDisplay),
         REG_JNI(register_android_media_ToneGenerator),
+        REG_JNI(register_android_media_audio_common_AidlConversion),
         REG_JNI(register_android_media_midi),
 
         REG_JNI(register_android_opengl_classes),
@@ -1654,6 +1659,8 @@
         REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader),
         REG_JNI(register_com_android_internal_os_KernelSingleProcessCpuThreadReader),
         REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader),
+
+        REG_JNI(register_android_window_WindowInfosListener),
 };
 
 /*
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 701960e..4bee976 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -22,6 +22,7 @@
 # WindowManager
 per-file android_graphics_BLASTBufferQueue.cpp = file:/services/core/java/com/android/server/wm/OWNERS
 per-file android_view_Surface* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file android_window_WindowInfosListener.cpp = file:/services/core/java/com/android/server/wm/OWNERS
 
 # Resources
 per-file android_content_res_* = file:/core/java/android/content/res/OWNERS
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index d4ae6d7..3e31b46 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -139,6 +139,11 @@
     }
 }
 
+static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+    return queue->getLastAcquiredFrameNum();
+}
+
 static const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         // clang-format off
@@ -151,7 +156,8 @@
         {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
         {"nativeSetTransactionCompleteCallback",
                 "(JJLandroid/graphics/BLASTBufferQueue$TransactionCompleteCallback;)V",
-                (void*)nativeSetTransactionCompleteCallback}
+                (void*)nativeSetTransactionCompleteCallback},
+        {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
         // clang-format on
 };
 
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 995bfa9..24d3531 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -28,6 +28,8 @@
 namespace android {
 
 static struct {
+    jclass clazz;
+    jmethodID ctor;
     jfieldID ptr;
     jfieldID name;
     jfieldID dispatchingTimeoutMillis;
@@ -101,6 +103,15 @@
     return *handle;
 }
 
+jobject android_view_InputApplicationHandle_fromInputApplicationInfo(
+        JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo) {
+    jobject binderObject = javaObjectForIBinder(env, inputApplicationInfo.token);
+    ScopedLocalRef<jstring> name(env, env->NewStringUTF(inputApplicationInfo.name.data()));
+    return env->NewObject(gInputApplicationHandleClassInfo.clazz,
+                          gInputApplicationHandleClassInfo.ctor, binderObject, name.get(),
+                          inputApplicationInfo.dispatchingTimeoutMillis);
+}
+
 // --- JNI ---
 
 static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
@@ -131,6 +142,10 @@
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
         LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
 
+#define GET_METHOD_ID(var, clazz, methodName, methodSignature)  \
+    var = env->GetMethodID(clazz, methodName, methodSignature); \
+    LOG_ALWAYS_FATAL_IF(!(var), "Unable to find method " methodName);
+
 int register_android_view_InputApplicationHandle(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "android/view/InputApplicationHandle",
             gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
@@ -139,6 +154,10 @@
 
     jclass clazz;
     FIND_CLASS(clazz, "android/view/InputApplicationHandle");
+    gInputApplicationHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+
+    GET_METHOD_ID(gInputApplicationHandleClassInfo.ctor, clazz, "<init>",
+                  "(Landroid/os/IBinder;Ljava/lang/String;J)V");
 
     GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
             "ptr", "J");
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h
index 7eb7ac4..5d88d8e 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.h
+++ b/core/jni/android_hardware_input_InputApplicationHandle.h
@@ -42,6 +42,9 @@
 extern std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
         JNIEnv* env, jobject inputApplicationHandleObj);
 
+extern jobject android_view_InputApplicationHandle_fromInputApplicationInfo(
+        JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo);
+
 } // namespace android
 
 #endif // _ANDROID_VIEW_INPUT_APPLICATION_HANDLE_H
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 3a09562..e4ef7d3 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -26,7 +26,9 @@
 #include <ui/Region.h>
 #include <utils/threads.h>
 
+#include <android/graphics/matrix.h>
 #include <gui/WindowInfo.h>
+#include "SkRegion.h"
 #include "android_hardware_input_InputApplicationHandle.h"
 #include "android_util_Binder.h"
 #include "core_jni_helpers.h"
@@ -44,6 +46,8 @@
 };
 
 static struct {
+    jclass clazz;
+    jmethodID ctor;
     jfieldID ptr;
     jfieldID inputApplicationHandle;
     jfieldID token;
@@ -71,8 +75,16 @@
     jfieldID displayId;
     jfieldID replaceTouchableRegionWithCrop;
     WeakRefHandleField touchableRegionSurfaceControl;
+    jfieldID transform;
+    jfieldID windowToken;
 } gInputWindowHandleClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+    jfieldID nativeRegion;
+} gRegionClassInfo;
+
 static Mutex gHandleMutex;
 
 
@@ -204,6 +216,14 @@
         mInfo.touchableRegionCropHandle.clear();
     }
 
+    jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken);
+    if (windowTokenObj) {
+        mInfo.windowToken = ibinderForJavaObject(env, windowTokenObj);
+        env->DeleteLocalRef(windowTokenObj);
+    } else {
+        mInfo.windowToken.clear();
+    }
+
     env->DeleteLocalRef(obj);
     return true;
 }
@@ -233,6 +253,81 @@
     return handle;
 }
 
+jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowInfo windowInfo) {
+    ScopedLocalRef<jobject>
+            applicationHandle(env,
+                              android_view_InputApplicationHandle_fromInputApplicationInfo(
+                                      env, windowInfo.applicationInfo));
+
+    jobject inputWindowHandle =
+            env->NewObject(gInputWindowHandleClassInfo.clazz, gInputWindowHandleClassInfo.ctor,
+                           applicationHandle.get(), windowInfo.displayId);
+    env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token,
+                        javaObjectForIBinder(env, windowInfo.token));
+    env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name,
+                        env->NewStringUTF(windowInfo.name.data()));
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
+                     static_cast<uint32_t>(windowInfo.flags.get()));
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType,
+                     static_cast<int32_t>(windowInfo.type));
+    env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis,
+                      std::chrono::duration_cast<std::chrono::milliseconds>(
+                              windowInfo.dispatchingTimeout)
+                              .count());
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameLeft,
+                     windowInfo.frameLeft);
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameTop, windowInfo.frameTop);
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameRight,
+                     windowInfo.frameRight);
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameBottom,
+                     windowInfo.frameBottom);
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.surfaceInset,
+                     windowInfo.surfaceInset);
+    env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.scaleFactor,
+                       windowInfo.globalScaleFactor);
+
+    SkRegion* region = new SkRegion();
+    for (const auto& r : windowInfo.touchableRegion) {
+        region->op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op);
+    }
+    ScopedLocalRef<jobject> regionObj(env,
+                                      env->NewObject(gRegionClassInfo.clazz,
+                                                     gRegionClassInfo.ctor));
+    env->SetLongField(regionObj.get(), gRegionClassInfo.nativeRegion,
+                      reinterpret_cast<jlong>(region));
+    env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
+                        regionObj.get());
+
+    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible,
+                         windowInfo.visible);
+    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable,
+                         windowInfo.focusable);
+    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper,
+                         windowInfo.hasWallpaper);
+    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, windowInfo.paused);
+    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay,
+                         windowInfo.trustedOverlay);
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
+                     static_cast<int32_t>(windowInfo.touchOcclusionMode));
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid, windowInfo.ownerUid);
+    env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName,
+                        env->NewStringUTF(windowInfo.packageName.data()));
+    env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputFeatures,
+                     static_cast<int32_t>(windowInfo.inputFeatures.get()));
+
+    float transformVals[9];
+    for (int i = 0; i < 9; i++) {
+        transformVals[i] = windowInfo.transform[i % 3][i / 3];
+    }
+    ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformVals));
+    env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.transform, matrixObj.get());
+
+    env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.windowToken,
+                        javaObjectForIBinder(env, windowInfo.windowToken));
+
+    return inputWindowHandle;
+}
 
 // --- JNI ---
 
@@ -275,6 +370,10 @@
 
     jclass clazz;
     FIND_CLASS(clazz, "android/view/InputWindowHandle");
+    gInputWindowHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+
+    GET_METHOD_ID(gInputWindowHandleClassInfo.ctor, clazz, "<init>",
+                  "(Landroid/view/InputApplicationHandle;I)V");
 
     GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
             "ptr", "J");
@@ -351,6 +450,12 @@
     GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
             "replaceTouchableRegionWithCrop", "Z");
 
+    GET_FIELD_ID(gInputWindowHandleClassInfo.transform, clazz, "transform",
+                 "Landroid/graphics/Matrix;");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.windowToken, clazz, "windowToken",
+                 "Landroid/os/IBinder;");
+
     jclass weakRefClazz;
     FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");
 
@@ -365,6 +470,11 @@
     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject,
         surfaceControlClazz, "mNativeObject", "J");
 
+    jclass regionClazz;
+    FIND_CLASS(regionClazz, "android/graphics/Region");
+    gRegionClassInfo.clazz = MakeGlobalRefOrDie(env, regionClazz);
+    GET_METHOD_ID(gRegionClassInfo.ctor, gRegionClassInfo.clazz, "<init>", "()V");
+    GET_FIELD_ID(gRegionClassInfo.nativeRegion, gRegionClassInfo.clazz, "mNativeRegion", "J");
     return 0;
 }
 
diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h
index 635480fc..408e0f1 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.h
+++ b/core/jni/android_hardware_input_InputWindowHandle.h
@@ -40,6 +40,9 @@
 extern sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
         JNIEnv* env, jobject inputWindowHandleObj);
 
+extern jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env,
+                                                             gui::WindowInfo windowInfo);
+
 } // namespace android
 
 #endif // _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H
diff --git a/core/jni/android_media_AudioDeviceAttributes.cpp b/core/jni/android_media_AudioDeviceAttributes.cpp
index 2a16dce..6879a60 100644
--- a/core/jni/android_media_AudioDeviceAttributes.cpp
+++ b/core/jni/android_media_AudioDeviceAttributes.cpp
@@ -24,6 +24,11 @@
 
 static jclass gAudioDeviceAttributesClass;
 static jmethodID gAudioDeviceAttributesCstor;
+static struct {
+    jfieldID mAddress;
+    jfieldID mNativeType;
+    // other fields unused by JNI
+} gAudioDeviceAttributesFields;
 
 namespace android {
 
@@ -33,12 +38,25 @@
     jint jNativeType = (jint)devTypeAddr->mType;
     ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->getAddress()));
 
-    *jAudioDeviceAttributes = env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor,
-            jNativeType, jAddress.get());
+    *jAudioDeviceAttributes =
+        env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor,
+                       jNativeType, jAddress.get());
 
     return jStatus;
 }
 
+jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr,
+                                       const jobject jAudioDeviceAttributes) {
+    devTypeAddr->mType = (audio_devices_t)env->GetIntField(jAudioDeviceAttributes,
+                         gAudioDeviceAttributesFields.mNativeType);
+
+    jstring jAddress = (jstring)env->GetObjectField(jAudioDeviceAttributes,
+                       gAudioDeviceAttributesFields.mAddress);
+    devTypeAddr->setAddress(ScopedUtfChars(env, jAddress).c_str());
+
+    return AUDIO_JAVA_SUCCESS;
+}
+
 } // namespace android
 
 int register_android_media_AudioDeviceAttributes(JNIEnv *env) {
@@ -48,5 +66,10 @@
     gAudioDeviceAttributesCstor =
             GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>", "(ILjava/lang/String;)V");
 
+    gAudioDeviceAttributesFields.mNativeType =
+            GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mNativeType", "I");
+    gAudioDeviceAttributesFields.mAddress =
+            GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mAddress", "Ljava/lang/String;");
+
     return 0;
 }
diff --git a/core/jni/android_media_AudioDeviceAttributes.h b/core/jni/android_media_AudioDeviceAttributes.h
index b49d9ba..4a1f40d 100644
--- a/core/jni/android_media_AudioDeviceAttributes.h
+++ b/core/jni/android_media_AudioDeviceAttributes.h
@@ -28,6 +28,9 @@
 
 extern jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAttributes,
                                         const AudioDeviceTypeAddr *devTypeAddr);
+
+extern jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr,
+                                        const jobject jAudioDeviceAttributes);
 } // namespace android
 
 #endif
\ No newline at end of file
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a6d038d..268871b 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -27,6 +27,8 @@
 #include "core_jni_helpers.h"
 
 #include <android/media/AudioVibratorInfo.h>
+#include <android/media/INativeSpatializerCallback.h>
+#include <android/media/ISpatializer.h>
 #include <audiomanager/AudioManager.h>
 #include <media/AudioContainers.h>
 #include <media/AudioPolicy.h>
@@ -2025,6 +2027,18 @@
     AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback);
 }
 
+void javaAudioFormatToNativeAudioConfig(JNIEnv *env, audio_config_t *nConfig,
+                                       const jobject jFormat, bool isInput) {
+    *nConfig = AUDIO_CONFIG_INITIALIZER;
+    nConfig->format = audioFormatToNative(env->GetIntField(jFormat, gAudioFormatFields.mEncoding));
+    nConfig->sample_rate = env->GetIntField(jFormat, gAudioFormatFields.mSampleRate);
+    jint jChannelMask = env->GetIntField(jFormat, gAudioFormatFields.mChannelMask);
+    if (isInput) {
+        nConfig->channel_mask = inChannelMaskToNative(jChannelMask);
+    } else {
+        nConfig->channel_mask = outChannelMaskToNative(jChannelMask);
+    }
+}
 
 static jint convertAudioMixToNative(JNIEnv *env,
                                     AudioMix *nAudioMix,
@@ -2045,13 +2059,7 @@
     nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
 
     jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
-    nAudioMix->mFormat = AUDIO_CONFIG_INITIALIZER;
-    nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
-                                                     gAudioFormatFields.mSampleRate);
-    nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
-                                                     gAudioFormatFields.mChannelMask));
-    nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat,
-                                                     gAudioFormatFields.mEncoding));
+    javaAudioFormatToNativeAudioConfig(env, &nAudioMix->mFormat, jFormat, false /*isInput*/);
     env->DeleteLocalRef(jFormat);
 
     jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
@@ -2432,6 +2440,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;
@@ -2708,6 +2722,58 @@
     return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
 }
 
+static jobject android_media_AudioSystem_getSpatializer(JNIEnv *env, jobject thiz,
+                                                       jobject jISpatializerCallback) {
+    sp<media::INativeSpatializerCallback> nISpatializerCallback
+            = interface_cast<media::INativeSpatializerCallback>(
+                    ibinderForJavaObject(env, jISpatializerCallback));
+    sp<media::ISpatializer> nSpatializer;
+    status_t status = AudioSystem::getSpatializer(nISpatializerCallback,
+                                        &nSpatializer);
+    if (status != NO_ERROR) {
+        return nullptr;
+    }
+    return javaObjectForIBinder(env, IInterface::asBinder(nSpatializer));
+}
+
+static jboolean android_media_AudioSystem_canBeSpatialized(JNIEnv *env, jobject thiz,
+                                                       jobject jaa, jobject jFormat,
+                                                       jobjectArray jDeviceArray) {
+    JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+    jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+    if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+       return false;
+    }
+
+    AudioDeviceTypeAddrVector nDevices;
+
+    const size_t numDevices = env->GetArrayLength(jDeviceArray);
+    for (size_t i = 0;  i < numDevices; ++i) {
+        AudioDeviceTypeAddr device;
+        jobject jDevice  = env->GetObjectArrayElement(jDeviceArray, i);
+        if (jDevice == nullptr) {
+            return false;
+        }
+        jStatus = createAudioDeviceTypeAddrFromJava(env, &device, jDevice);
+        if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+            return false;
+        }
+        nDevices.push_back(device);
+    }
+
+    audio_config_t nConfig;
+    javaAudioFormatToNativeAudioConfig(env, &nConfig, jFormat, false /*isInput*/);
+
+    bool canBeSpatialized;
+    status_t status =
+            AudioSystem::canBeSpatialized(paa.get(), &nConfig, nDevices, &canBeSpatialized);
+    if (status != NO_ERROR) {
+        ALOGW("%s native returned error %d", __func__, status);
+        return false;
+    }
+    return canBeSpatialized;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] =
@@ -2804,6 +2870,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},
@@ -2842,7 +2910,15 @@
           (void *)android_media_AudioSystem_removeUserIdDeviceAffinities},
          {"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid},
          {"setVibratorInfos", "(Ljava/util/List;)I",
-          (void *)android_media_AudioSystem_setVibratorInfos}};
+          (void *)android_media_AudioSystem_setVibratorInfos},
+         {"nativeGetSpatializer",
+          "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
+          (void *)android_media_AudioSystem_getSpatializer},
+         {"canBeSpatialized",
+          "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
+          "[Landroid/media/AudioDeviceAttributes;)Z",
+          (void *)android_media_AudioSystem_canBeSpatialized}};
+
 
 static const JNINativeMethod gEventHandlerMethods[] = {
     {"native_setup",
diff --git a/core/jni/android_media_audio_common_AidlConversion.cpp b/core/jni/android_media_audio_common_AidlConversion.cpp
new file mode 100644
index 0000000..2ef817c
--- /dev/null
+++ b/core/jni/android_media_audio_common_AidlConversion.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AidlConversion"
+
+#include <sstream>
+#include <type_traits>
+
+#include <android_os_Parcel.h>
+#include <binder/Parcel.h>
+#include <jni.h>
+#include <log/log.h>
+#include <media/AidlConversion.h>
+#include <system/audio.h>
+
+#include "core_jni_helpers.h"
+
+namespace {
+
+using namespace android;
+using media::audio::common::AudioChannelLayout;
+using media::audio::common::AudioEncapsulationMode;
+using media::audio::common::AudioFormatDescription;
+using media::audio::common::AudioStreamType;
+using media::audio::common::AudioUsage;
+
+#define PACKAGE "android/media/audio/common"
+#define CLASSNAME PACKAGE "/AidlConversion"
+
+// Used for creating messages.
+template <typename T>
+struct type_info {
+    static constexpr const char* name = "";
+};
+#define TYPE_NAME_QUOTE(x) #x
+#define TYPE_NAME_STRINGIFY(x) TYPE_NAME_QUOTE(x)
+#define TYPE_NAME(n)                                                \
+    template <>                                                     \
+    struct type_info<n> {                                           \
+        static constexpr const char* name = TYPE_NAME_STRINGIFY(n); \
+    }
+
+TYPE_NAME(AudioChannelLayout);
+TYPE_NAME(AudioEncapsulationMode);
+TYPE_NAME(AudioFormatDescription);
+TYPE_NAME(AudioStreamType);
+TYPE_NAME(AudioUsage);
+TYPE_NAME(audio_encapsulation_mode_t);
+TYPE_NAME(audio_stream_type_t);
+TYPE_NAME(audio_usage_t);
+
+template <typename AidlType, typename LegacyType, typename ConvFunc>
+int aidl2legacy(JNIEnv* env, AidlType aidl, const ConvFunc& conv, LegacyType fallbackValue) {
+    const auto result = conv(aidl);
+    if (result.ok()) {
+        return result.value();
+    }
+    std::ostringstream msg;
+    msg << "Failed to convert " << type_info<AidlType>::name << " value "
+        << static_cast<std::underlying_type_t<AidlType>>(aidl);
+    jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
+    return fallbackValue;
+}
+
+template <typename LegacyType, typename AidlType, typename ConvFunc>
+int legacy2aidl(JNIEnv* env, LegacyType legacy, const ConvFunc& conv, AidlType fallbackValue) {
+    const auto result = conv(legacy);
+    if (result.ok()) {
+        return static_cast<std::underlying_type_t<AidlType>>(result.value());
+    }
+    std::ostringstream msg;
+    msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
+    jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
+    return static_cast<std::underlying_type_t<AidlType>>(fallbackValue);
+}
+
+template <typename AidlType, typename ConvFunc>
+int aidlParcel2legacy(JNIEnv* env, jobject jParcel, const ConvFunc& conv, int fallbackValue) {
+    if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
+        AidlType aidl{};
+        if (status_t status = aidl.readFromParcel(parcel); status == OK) {
+            auto legacy = conv(aidl);
+            if (legacy.ok()) {
+                return legacy.value();
+            }
+        } else {
+            ALOGE("aidl2legacy: Failed to read from parcel: %s", statusToString(status).c_str());
+        }
+        std::ostringstream msg;
+        msg << "Failed to convert " << type_info<AidlType>::name << " value " << aidl.toString();
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
+    } else {
+        ALOGE("aidl2legacy: Failed to retrieve the native parcel from Java parcel");
+    }
+    return fallbackValue;
+}
+
+template <typename LegacyType, typename ConvFunc>
+jobject legacy2aidlParcel(JNIEnv* env, LegacyType legacy, const ConvFunc& conv) {
+    auto aidl = conv(legacy);
+    if (!aidl.ok()) {
+        std::ostringstream msg;
+        msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
+        return 0;
+    }
+    if (jobject jParcel = createJavaParcelObject(env); jParcel != 0) {
+        if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
+            if (status_t status = aidl.value().writeToParcel(parcel); status == OK) {
+                parcel->setDataPosition(0);
+                return jParcel;
+            } else {
+                ALOGE("legacy2aidl: Failed to write to parcel: %s, aidl value: %s",
+                      statusToString(status).c_str(), aidl.value().toString().c_str());
+            }
+        } else {
+            ALOGE("legacy2aidl: Failed to retrieve the native parcel from Java parcel");
+        }
+        env->DeleteLocalRef(jParcel);
+    } else {
+        ALOGE("legacy2aidl: Failed to create Java parcel");
+    }
+    return 0;
+}
+
+int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(JNIEnv* env, jobject,
+                                                               jobject jParcel, jboolean isInput) {
+    return aidlParcel2legacy<AudioChannelLayout>(
+            env, jParcel,
+            [isInput](const AudioChannelLayout& l) {
+                return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
+            },
+            AUDIO_CHANNEL_INVALID);
+}
+
+jobject legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
+        JNIEnv* env, jobject, int /*audio_channel_mask_t*/ legacy, jboolean isInput) {
+    return legacy2aidlParcel(
+            env, static_cast<audio_channel_mask_t>(legacy), [isInput](audio_channel_mask_t m) {
+                return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
+            });
+}
+
+int aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(JNIEnv* env, jobject,
+                                                             jobject jParcel) {
+    return aidlParcel2legacy<
+            AudioFormatDescription>(env, jParcel, aidl2legacy_AudioFormatDescription_audio_format_t,
+                                    AUDIO_FORMAT_INVALID);
+}
+
+jobject legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(JNIEnv* env, jobject,
+                                                                 int /*audio_format_t*/ legacy) {
+    return legacy2aidlParcel(env, static_cast<audio_format_t>(legacy),
+                             legacy2aidl_audio_format_t_AudioFormatDescription);
+}
+
+jint aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(JNIEnv* env, jobject,
+                                                                   jint aidl) {
+    return aidl2legacy(env, AudioEncapsulationMode(static_cast<int32_t>(aidl)),
+                       android::aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t,
+                       AUDIO_ENCAPSULATION_MODE_NONE);
+}
+
+jint legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(JNIEnv* env, jobject,
+                                                                   jint legacy) {
+    return legacy2aidl(env, static_cast<audio_encapsulation_mode_t>(legacy),
+                       android::legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode,
+                       AudioEncapsulationMode::INVALID);
+}
+
+jint aidl2legacy_AudioStreamType_audio_stream_type_t(JNIEnv* env, jobject, jint aidl) {
+    return aidl2legacy(env, AudioStreamType(static_cast<int32_t>(aidl)),
+                       android::aidl2legacy_AudioStreamType_audio_stream_type_t,
+                       AUDIO_STREAM_DEFAULT);
+}
+
+jint legacy2aidl_audio_stream_type_t_AudioStreamType(JNIEnv* env, jobject, jint legacy) {
+    return legacy2aidl(env, static_cast<audio_stream_type_t>(legacy),
+                       android::legacy2aidl_audio_stream_type_t_AudioStreamType,
+                       AudioStreamType::INVALID);
+}
+
+jint aidl2legacy_AudioUsage_audio_usage_t(JNIEnv* env, jobject, jint aidl) {
+    return aidl2legacy(env, AudioUsage(static_cast<int32_t>(aidl)),
+                       android::aidl2legacy_AudioUsage_audio_usage_t, AUDIO_USAGE_UNKNOWN);
+}
+
+jint legacy2aidl_audio_usage_t_AudioUsage(JNIEnv* env, jobject, jint legacy) {
+    return legacy2aidl(env, static_cast<audio_usage_t>(legacy),
+                       android::legacy2aidl_audio_usage_t_AudioUsage, AudioUsage::INVALID);
+}
+
+const JNINativeMethod gMethods[] = {
+        {"aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t", "(Landroid/os/Parcel;Z)I",
+         reinterpret_cast<void*>(aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t)},
+        {"legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel", "(IZ)Landroid/os/Parcel;",
+         reinterpret_cast<void*>(legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel)},
+        {"aidl2legacy_AudioFormatDescription_Parcel_audio_format_t", "(Landroid/os/Parcel;)I",
+         reinterpret_cast<void*>(aidl2legacy_AudioFormatDescription_Parcel_audio_format_t)},
+        {"legacy2aidl_audio_format_t_AudioFormatDescription_Parcel", "(I)Landroid/os/Parcel;",
+         reinterpret_cast<void*>(legacy2aidl_audio_format_t_AudioFormatDescription_Parcel)},
+        {"aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t", "(I)I",
+         reinterpret_cast<void*>(aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t)},
+        {"legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode", "(I)I",
+         reinterpret_cast<void*>(legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode)},
+        {"aidl2legacy_AudioStreamType_audio_stream_type_t", "(I)I",
+         reinterpret_cast<void*>(aidl2legacy_AudioStreamType_audio_stream_type_t)},
+        {"legacy2aidl_audio_stream_type_t_AudioStreamType", "(I)I",
+         reinterpret_cast<void*>(legacy2aidl_audio_stream_type_t_AudioStreamType)},
+        {"aidl2legacy_AudioUsage_audio_usage_t", "(I)I",
+         reinterpret_cast<void*>(aidl2legacy_AudioUsage_audio_usage_t)},
+        {"legacy2aidl_audio_usage_t_AudioUsage", "(I)I",
+         reinterpret_cast<void*>(legacy2aidl_audio_usage_t_AudioUsage)},
+};
+
+} // namespace
+
+int register_android_media_audio_common_AidlConversion(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, CLASSNAME, gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_os_ServiceManager.cpp b/core/jni/android_os_ServiceManager.cpp
index c747949..d642d0e 100644
--- a/core/jni/android_os_ServiceManager.cpp
+++ b/core/jni/android_os_ServiceManager.cpp
@@ -29,11 +29,8 @@
 
 // Native because we have a client-side wait in waitForService() and we do not
 // want an unnecessary second copy of it.
-static jobject android_os_ServiceManager_waitForService(
-        JNIEnv *env,
-        jclass /* clazzObj */,
-        jstring serviceNameObj) {
-
+static jobject android_os_ServiceManager_waitForServiceNative(JNIEnv* env, jclass /* clazzObj */,
+                                                              jstring serviceNameObj) {
     const jchar* serviceName = env->GetStringCritical(serviceNameObj, nullptr);
     if (!serviceName) {
         jniThrowNullPointerException(env, nullptr);
@@ -55,12 +52,9 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod method_table[] = {
-     /* name, signature, funcPtr */
-    {
-        "waitForService",
-        "(Ljava/lang/String;)Landroid/os/IBinder;",
-        (void*)android_os_ServiceManager_waitForService
-    },
+        /* name, signature, funcPtr */
+        {"waitForServiceNative", "(Ljava/lang/String;)Landroid/os/IBinder;",
+         (void*)android_os_ServiceManager_waitForServiceNative},
 };
 
 int register_android_os_ServiceManager(JNIEnv* env) {
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index e93b00d..86d7810 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -92,6 +92,7 @@
   jfieldID mSmallestScreenWidthDpOffset;
   jfieldID mScreenWidthDpOffset;
   jfieldID mScreenHeightDpOffset;
+  jfieldID mScreenLayoutOffset;
 } gConfigurationOffsets;
 
 static struct arraymap_offsets_t {
@@ -1019,6 +1020,7 @@
                    config.smallestScreenWidthDp);
   env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
   env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
+  env->SetIntField(result, gConfigurationOffsets.mScreenLayoutOffset, config.screenLayout);
   return result;
 }
 
@@ -1553,6 +1555,8 @@
       GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
   gConfigurationOffsets.mScreenHeightDpOffset =
       GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
+  gConfigurationOffsets.mScreenLayoutOffset =
+          GetFieldIDOrDie(env, configurationClass, "screenLayout", "I");
 
   jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
   gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index dd62bb1..4d8d4db 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -261,8 +261,12 @@
         sprintf(proc_path, "/proc/%d/cmdline", pid);
         fd = open(proc_path, O_RDONLY | O_CLOEXEC);
         if (fd >= 0) {
-            int rc = read(fd, cmdline, sizeof(cmdline)-1);
-            cmdline[rc] = 0;
+            ssize_t rc = read(fd, cmdline, sizeof(cmdline) - 1);
+            if (rc < 0) {
+                ALOGE("read /proc/%d/cmdline (%s)", pid, strerror(errno));
+            } else {
+                cmdline[rc] = 0;
+            }
             close(fd);
         }
 
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/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 8177ec6..2ef9632 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -98,9 +98,7 @@
     ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
     jobject eventObj =
             env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
-                                        event->getId(),
-                                        nanoseconds_to_milliseconds(event->getDownTime()),
-                                        nanoseconds_to_milliseconds(event->getEventTime()),
+                                        event->getId(), event->getDownTime(), event->getEventTime(),
                                         event->getAction(), event->getKeyCode(),
                                         event->getRepeatCount(), event->getMetaState(),
                                         event->getDeviceId(), event->getScanCode(),
@@ -136,8 +134,7 @@
     jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
 
     event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
-                      metaState, repeatCount, milliseconds_to_nanoseconds(downTime),
-                      milliseconds_to_nanoseconds(eventTime));
+                      metaState, repeatCount, downTime, eventTime);
     return OK;
 }
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 0957067..869b53d 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -449,6 +449,11 @@
                         int(changeFrameRateStrategy));
 }
 
+static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    sp<Surface> surface(reinterpret_cast<Surface*>(nativeObject));
+    surface->destroy();
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gSurfaceMethods[] = {
@@ -477,6 +482,7 @@
         {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
         {"nativeSetFrameRate", "(JFII)I", (void*)nativeSetFrameRate},
         {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue},
+        {"nativeDestroy", "(J)V", (void*)nativeDestroy},
 };
 
 int register_android_view_Surface(JNIEnv* env)
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index f63c0e5..eeb6ce5 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -814,7 +814,7 @@
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    transaction->setLayerStack(ctrl, layerStack);
+    transaction->setLayerStack(ctrl, ui::LayerStack::fromValue(layerStack));
 }
 
 static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -1013,7 +1013,7 @@
 
     {
         auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-        transaction->setDisplayLayerStack(token, layerStack);
+        transaction->setDisplayLayerStack(token, ui::LayerStack::fromValue(layerStack));
     }
 }
 
@@ -1815,6 +1815,12 @@
     return toRotationInt(ui::Transform::toRotation((transformHintRotationFlags)));
 }
 
+static jint nativeGetLayerId(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) {
+    sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl*>(nativeSurfaceControl));
+
+    return surface->getLayerId();
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -2010,6 +2016,8 @@
             (void*)nativeGetTransformHint },
     {"nativeSetTrustedOverlay", "(JJZ)V",
             (void*)nativeSetTrustedOverlay },
+    {"nativeGetLayerId", "(J)I",
+            (void*)nativeGetLayerId },
         // clang-format on
 };
 
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
new file mode 100644
index 0000000..ab88b53
--- /dev/null
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "WindowInfosListener"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+
+#include "android_hardware_input_InputWindowHandle.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using gui::WindowInfo;
+
+namespace {
+
+static struct {
+    jclass clazz;
+    jmethodID onWindowInfosChanged;
+} gListenerClassInfo;
+
+static jclass gInputWindowHandleClass;
+
+struct WindowInfosListener : public gui::WindowInfosListener {
+    WindowInfosListener(JNIEnv* env, jobject listener)
+          : mListener(env->NewWeakGlobalRef(listener)) {}
+
+    void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onWindowInfoChanged.");
+
+        jobject listener = env->NewGlobalRef(mListener);
+        if (listener == nullptr) {
+            // Weak reference went out of scope
+            return;
+        }
+
+        jobjectArray jWindowHandlesArray =
+                env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
+        for (int i = 0; i < windowInfos.size(); i++) {
+            ScopedLocalRef<jobject>
+                    jWindowHandle(env,
+                                  android_view_InputWindowHandle_fromWindowInfo(env,
+                                                                                windowInfos[i]));
+            env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get());
+        }
+
+        env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged, jWindowHandlesArray);
+        env->DeleteGlobalRef(listener);
+
+        if (env->ExceptionCheck()) {
+            ALOGE("WindowInfosListener.onWindowInfosChanged() failed.");
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+    }
+
+    ~WindowInfosListener() override {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->DeleteWeakGlobalRef(mListener);
+    }
+
+private:
+    jweak mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+    WindowInfosListener* listener = new WindowInfosListener(env, obj);
+    listener->incStrong((void*)nativeCreate);
+    return reinterpret_cast<jlong>(listener);
+}
+
+void destroyNativeService(void* ptr) {
+    WindowInfosListener* listener = reinterpret_cast<WindowInfosListener*>(ptr);
+    listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
+    SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
+    SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
+}
+
+static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
+}
+
+const JNINativeMethod gMethods[] = {
+        /* name, signature, funcPtr */
+        {"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate},
+        {"nativeRegister", "(J)V", (void*)nativeRegister},
+        {"nativeUnregister", "(J)V", (void*)nativeUnregister},
+        {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}};
+
+} // namespace
+
+int register_android_window_WindowInfosListener(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/window/WindowInfosListener", gMethods,
+                                       NELEM(gMethods));
+    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    jclass clazz = env->FindClass("android/window/WindowInfosListener");
+    gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gListenerClassInfo.onWindowInfosChanged =
+            env->GetMethodID(gListenerClassInfo.clazz, "onWindowInfosChanged",
+                             "([Landroid/view/InputWindowHandle;)V");
+
+    clazz = env->FindClass("android/view/InputWindowHandle");
+    gInputWindowHandleClass = MakeGlobalRefOrDie(env, clazz);
+    return 0;
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_content_om_OverlayConfig.cpp b/core/jni/com_android_internal_content_om_OverlayConfig.cpp
index 6aa7c10..b37269c 100644
--- a/core/jni/com_android_internal_content_om_OverlayConfig.cpp
+++ b/core/jni/com_android_internal_content_om_OverlayConfig.cpp
@@ -73,13 +73,13 @@
   }
 
   if (result->status != 0) {
-    LOG(ERROR) << "idmap2: " << result->stderr;
-    return nullptr;
+      LOG(ERROR) << "idmap2: " << result->stderr_str;
+      return nullptr;
   }
 
   // Return the paths of the idmaps created or updated during the idmap invocation.
   std::vector<std::string> idmap_paths;
-  std::istringstream input(result->stdout);
+  std::istringstream input(result->stdout_str);
   std::string path;
   while (std::getline(input, path)) {
     idmap_paths.push_back(path);
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
new file mode 100644
index 0000000..953902a
--- /dev/null
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <cstring>
+#include "LongArrayMultiStateCounter.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static jlong native_init(jint stateCount, jint arrayLength, jint initialState, jlong timestamp) {
+    battery::LongArrayMultiStateCounter *counter =
+            new battery::LongArrayMultiStateCounter(stateCount, initialState,
+                                                    std::vector<uint64_t>(arrayLength), timestamp);
+    return reinterpret_cast<jlong>(counter);
+}
+
+static void native_dispose(void *nativePtr) {
+    battery::LongArrayMultiStateCounter *counter =
+            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+    delete counter;
+}
+
+static jlong native_getReleaseFunc() {
+    return reinterpret_cast<jlong>(native_dispose);
+}
+
+static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
+    battery::LongArrayMultiStateCounter *counter =
+            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+    counter->setState(state, timestamp);
+}
+
+static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativePtr,
+                                jlong timestamp) {
+    battery::LongArrayMultiStateCounter *counter =
+            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+    std::vector<uint64_t> *vector =
+            reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
+
+    counter->updateValue(*vector, timestamp);
+}
+
+static void native_getCounts(jlong nativePtr, jlong longArrayContainerNativePtr, jint state) {
+    battery::LongArrayMultiStateCounter *counter =
+            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+    std::vector<uint64_t> *vector =
+            reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
+
+    *vector = counter->getCount(state);
+}
+
+static jobject native_toString(JNIEnv *env, jlong nativePtr, jobject self) {
+    battery::LongArrayMultiStateCounter *counter =
+            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+    return env->NewStringUTF(counter->toString().c_str());
+}
+
+static jlong native_init_LongArrayContainer(jint length) {
+    return reinterpret_cast<jlong>(new std::vector<uint64_t>(length));
+}
+
+static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
+        // @CriticalNative
+        {"native_init", "(IIIJ)J", (void *)native_init},
+        // @CriticalNative
+        {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
+        // @CriticalNative
+        {"native_setState", "(JIJ)V", (void *)native_setState},
+        // @CriticalNative
+        {"native_updateValues", "(JJJ)V", (void *)native_updateValues},
+        // @CriticalNative
+        {"native_getCounts", "(JJI)V", (void *)native_getCounts},
+        // @FastNative
+        {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
+};
+
+/////////////////////// LongArrayMultiStateCounter.LongArrayContainer ////////////////////////
+
+static void native_dispose_LongArrayContainer(jlong nativePtr) {
+    std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+    delete vector;
+}
+
+static jlong native_getReleaseFunc_LongArrayContainer() {
+    return reinterpret_cast<jlong>(native_dispose_LongArrayContainer);
+}
+
+static void native_setValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
+                                                jlongArray jarray) {
+    std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+    ScopedLongArrayRO scopedArray(env, jarray);
+    const uint64_t *array = reinterpret_cast<const uint64_t *>(scopedArray.get());
+    uint8_t size = scopedArray.size();
+
+    // Boundary checks are performed in the Java layer
+    std::copy(array, array + size, vector->data());
+}
+
+static void native_getValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
+                                                jlongArray jarray) {
+    std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+    ScopedLongArrayRW scopedArray(env, jarray);
+
+    // Boundary checks are performed in the Java layer
+    std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
+}
+
+static const JNINativeMethod g_LongArrayContainer_methods[] = {
+        // @CriticalNative
+        {"native_init", "(I)J", (void *)native_init_LongArrayContainer},
+        // @CriticalNative
+        {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc_LongArrayContainer},
+        // @FastNative
+        {"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
+        // @FastNative
+        {"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
+};
+
+int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
+    // 0 represents success, thus "|" and not "&"
+    return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter",
+                                g_LongArrayMultiStateCounter_methods,
+                                NELEM(g_LongArrayMultiStateCounter_methods)) |
+            RegisterMethodsOrDie(env,
+                                 "com/android/internal/os/LongArrayMultiStateCounter"
+                                 "$LongArrayContainer",
+                                 g_LongArrayContainer_methods, NELEM(g_LongArrayContainer_methods));
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index bed0aae..ce44e07 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -62,7 +62,6 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
-#include <sys/utsname.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
@@ -850,26 +849,6 @@
   }
 }
 
-static bool NeedsNoRandomizeWorkaround() {
-#if !defined(__arm__)
-    return false;
-#else
-    int major;
-    int minor;
-    struct utsname uts;
-    if (uname(&uts) == -1) {
-        return false;
-    }
-
-    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
-        return false;
-    }
-
-    // Kernels before 3.4.* need the workaround.
-    return (major < 3) || ((major == 3) && (minor < 4));
-#endif
-}
-
 // Utility to close down the Zygote socket file descriptors while
 // the child is still running as root with Zygote's privileges.  Each
 // descriptor (if any) is closed via dup3(), replacing it with a valid
@@ -1740,15 +1719,6 @@
     // runtime.
     runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
 
-    if (NeedsNoRandomizeWorkaround()) {
-        // Work around ARM kernel ASLR lossage (http://b/5817320).
-        int old_personality = personality(0xffffffff);
-        int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
-        if (new_personality == -1) {
-            ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
-        }
-    }
-
     SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
                     fail_fn);
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c3d1596..83e26f6 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -771,6 +771,8 @@
     optional SettingProto power_manager_constants = 93;
     reserved 94; // Used to be priv_app_oob_enabled
 
+    optional SettingProto power_button_long_press_duration_ms = 154 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     message PrepaidSetup {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -970,6 +972,7 @@
     optional SettingProto usb_mass_storage_enabled = 127 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto use_google_mail = 128 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto use_open_wifi_package = 129 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto uwb_enabled = 155 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto vt_ims_enabled = 130 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wait_for_debugger = 131 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
@@ -1063,5 +1066,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 154;
+    // Next tag = 156;
 }
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 1bba12f..ba4a5b0 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -79,7 +79,7 @@
         optional SettingProto accessibility_magnification_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto button_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_magnification_capability = 36 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        // Settings for accessibility button mode (navigation bar or floating action menu).
+        // Settings for accessibility button related config
         optional SettingProto accessibility_button_mode = 37 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_floating_menu_size = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_floating_menu_icon_type = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/proto/android/server/accessibilitytrace.proto b/core/proto/android/server/accessibilitytrace.proto
index 41fecfd..0ce39ab 100644
--- a/core/proto/android/server/accessibilitytrace.proto
+++ b/core/proto/android/server/accessibilitytrace.proto
@@ -59,4 +59,5 @@
 
     optional AccessibilityDumpProto accessibility_service = 10;
     optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 11;
+    optional string cpu_stats = 12;
 }
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 0121bff..4af9d75 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -480,6 +480,7 @@
     optional SurfaceAnimatorProto surface_animator = 4;
     repeated WindowContainerChildProto children = 5;
     optional IdentifierProto identifier = 6;
+    optional .android.view.SurfaceControlProto surface_control = 7;
 }
 
 /* represents a generic child of a WindowContainer */
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 45f8c132..97097ff 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -72,6 +72,7 @@
     optional bool adb_enabled = 14;
     optional string kernel_state = 15;
     optional string kernel_function_list = 16;
+    optional string uevent = 17;
 }
 
 message UsbAccessoryProto {
@@ -315,6 +316,7 @@
     optional int32 parent_user_id = 1;
     repeated UsbSettingsDevicePreferenceProto device_preferences = 2;
     repeated UsbSettingsAccessoryPreferenceProto accessory_preferences = 3;
+    optional string intent = 4;
 }
 
 message UsbSettingsDevicePreferenceProto {
diff --git a/core/proto/android/view/surfacecontrol.proto b/core/proto/android/view/surfacecontrol.proto
index cbb243b..5a5f035 100644
--- a/core/proto/android/view/surfacecontrol.proto
+++ b/core/proto/android/view/surfacecontrol.proto
@@ -29,4 +29,5 @@
 
     optional int32 hash_code = 1;
     optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+    optional int32 layerId = 3;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f924229..85ae915 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3152,6 +3152,12 @@
     <permission android:name="android.permission.READ_DEVICE_CONFIG"
         android:protectionLevel="signature|preinstalled" />
 
+    <!-- @SystemApi @hide Allows applications like settings to read system-owned
+     application-specific locale configs.
+     <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.READ_APP_SPECIFIC_LOCALES"
+                android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to monitor {@link android.provider.Settings.Config} access.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 56d9a84..3666f48 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gebruik jou vingerafdruk of skermslot om voort te gaan"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdrukikoon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Gesigslot"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Kwessie met Gesigslot"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik jou gesig of skermslot om voort te gaan"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Gesig-ikoon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lees sinkroniseer-instellings"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Laat die program toe om die sinkroniseringinstellings van \'n rekening te lees. Byvoorbeeld, dit kan bepaal of die People-program met \'n rekening gesinkroniseer is."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Skakel kortpad vir toeganklikheidskenmerke aan?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"As jy albei volumesleutels vir \'n paar sekondes hou, skakel dit toeganklikheidkenmerke aan. Dit kan verander hoe jou toestel werk.\n\nHuidige kenmerke:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nJy kan geselekteerde kenmerke in Instellings en Toeganklikheid verander."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Skakel <xliff:g id="SERVICE">%1$s</xliff:g>-kortpad aan?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"As jy albei volumesleutels vir \'n paar sekondes hou, skakel dit <xliff:g id="SERVICE">%1$s</xliff:g>, \'n toeganklikheidkenmerk, aan. Dit kan verander hoe jou toestel werk.\n\nJy kan hierdie kortpad na \'n ander kenmerk in Instellings en Toeganklikheid verander."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Skakel aan"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 39a3d6e..fb4669c 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ለመቀጠል የጣት አሻራዎን ወይም የማያ ገጽ ቁልፍዎን ይጠቀሙ"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"የጣት አሻራ አዶ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"በመልክ መክፈት"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ከመልክ መክፈት ጋር በተያያዘ ችግር"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ለመቀጠል መልክዎን ወይም የማያ ገጽዎን መቆለፊያ ይጠቀሙ"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"የፊት አዶ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"የሥምሪያ ቅንብሮች አንብብ"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"መተግበሪያው የአንድ መለያ የማመሳሰል ቅንብሮችን እንዲያነብ ይፈቅድለታል። ለምሳሌ ይህ የሰዎች መተግበሪያ ከመለያ ጋር መመሳሰሉን አለመመሳሰሉን ሊወስን ይችላል።"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"አቋራጩ ሲበራ ሁለቱንም የድምጽ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"የተደራሽነት ባህሪዎች አቋራጭ ይብራ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ሁለቱንም የድምፅ ቁልፎች ወደ ታች ለጥቂት ሰከንዶች መያዝ የተደራሽነት ባሕሪያትን ያበራል። ይህ የእርስዎ መሣሪያ እንዴት እንደሚሠራ ሊለውጥ ይችላል።\n\nየአሁን ባሕሪያት፦\n<xliff:g id="SERVICE">%1$s</xliff:g>\nበቅንብሮች &gt; ተደራሽነት ውስጥ የተመረጡትን ባሕሪያት መለወጥ ይችላሉ።"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"የ<xliff:g id="SERVICE">%1$s</xliff:g> አቋራጭ ይብራ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ሁለቱንም የድምፅ ቁልፎች ወደ ታች ለጥቂት ሰከንዶች መያዝ የተደራሽነት ባሕሪያትን <xliff:g id="SERVICE">%1$s</xliff:g> ያበራል። ይህ የእርስዎ መሣሪያ እንዴት እንደሚሠራ ሊለውጥ ይችላል።\n\nበቅንብሮች &gt; ተደራሽነት ውስጥ ወደ ሌላ ባሕሪ ይህን አቋራጭ መለወጥ ይችላሉ።"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"አብራ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7e3f16b..a7aefa7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -341,7 +341,7 @@
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"استرداد محتوى النافذة"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"فحص محتوى نافذة يتم التفاعل معها"</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"تفعيل الاستكشاف باللمس"</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"سيتم قول العناصر التي تم النقر عليها بصوت عال ويمكن استكشاف الشاشة باستخدام الإيماءات."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"سيتم قول العناصر التي تم النقر عليها بصوت عالٍ ويمكن استكشاف الشاشة باستخدام الإيماءات."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"ملاحظة النص الذي تكتبه"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"يتضمن بيانات شخصية مثل أرقام بطاقات الائتمان وكلمات المرور."</string>
     <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"التحكم في تكبير الشاشة"</string>
@@ -621,6 +621,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"استخدام بصمة الإصبع أو قفل الشاشة للمتابعة"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"رمز بصمة الإصبع"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"فتح الجهاز بالتعرف على الوجه"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"مشكلة متعلّقة بميزة \"فتح الجهاز بالتعرف على الوجه\""</string>
@@ -673,6 +675,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"استخدام ميزة \"فتح القفل بالوجه\" أو ميزة \"قفل الشاشة\" للمتابعة"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"رمز الوجه"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"قراءة إعدادات المزامنة"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string>
@@ -1780,7 +1784,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"عند تفعيل الاختصار، يؤدي الضغط على زرّي التحكّم في مستوى الصوت معًا لمدة 3 ثوانٍ إلى تفعيل إحدى ميزات إمكانية الوصول."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"هل تريد تفعيل الاختصار لميزات إمكانية الوصول؟"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"يؤدي الضغط مع الاستمرار على كلا مفتاحَي التحكّم في مستوى الصوت لبضع ثوانٍ إلى تفعيل ميزات إمكانية الوصول. قد يؤدي هذا الإجراء إلى تغيير طريقة عمل جهازك.\n\nالميزات الحالية:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nيمكنك تغيير الميزات المحددة في الإعدادات &gt; إمكانية الوصول."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"هل تريد تفعيل اختصار <xliff:g id="SERVICE">%1$s</xliff:g>؟"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"‏يؤدي الضغط مع الاستمرار لبضع ثوانٍ على كلا مفتاحَي التحكّم في مستوى الصوت إلى تفعيل <xliff:g id="SERVICE">%1$s</xliff:g> وهي إحدى ميزات إمكانية الوصول. يمكن أن يؤدي هذا الإجراء إلى تغيير كيفية عمل جهازك.\n\nيمكنك تغيير هذا الاختصار لاستخدامه مع ميزة أخرى في الإعدادات &gt; أدوات تمكين الوصول."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"تفعيل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a398c35..7ea0542 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড OFFলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"কণ্ঠস্বৰ"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ডেটা"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ফেক্স"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"এছএমএছ"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেচ আনলক"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ফেচ আনলক ব্যৱহাৰ কৰোঁতে সমস্যা হৈছে"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"অব্যাহত ৰাখিবলৈ আপোনাৰ মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"মুখমণ্ডলৰ আইকন"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ছিংকৰ ছেটিংসমূহ পঢ়ক"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ কোনো একাউণ্টত ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string>
@@ -815,7 +819,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"কৰ্মস্থানৰ ম’বাইল নম্বৰ"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"কৰ্মস্থানৰ পেজাৰৰ নম্বৰ"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"সহায়ক"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"এমএমএছ"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"নিজৰ উপযোগিতা অনুযায়ী"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"জন্মদিন"</string>
@@ -848,7 +852,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"অন্যান্য"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"নিজৰ উপযোগিতা অনুযায়ী"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"নিজৰ উপযোগিতা অনুযায়ী"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"সহায়ক"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"ভাতৃ"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"শিশু"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"সংগী"</string>
@@ -1038,9 +1042,9 @@
     <string name="menu_space_shortcut_label" msgid="5949311515646872071">"স্পেচ"</string>
     <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"লিখক"</string>
     <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"মচক"</string>
-    <string name="search_go" msgid="2141477624421347086">"Search"</string>
-    <string name="search_hint" msgid="455364685740251925">"অনুসন্ধান কৰক…"</string>
-    <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+    <string name="search_go" msgid="2141477624421347086">"সন্ধান কৰক"</string>
+    <string name="search_hint" msgid="455364685740251925">"সন্ধান কৰক…"</string>
+    <string name="searchview_description_search" msgid="1045552007537359343">"সন্ধান কৰক"</string>
     <string name="searchview_description_query" msgid="7430242366971716338">"প্ৰশ্নৰ সন্ধান কৰক"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"প্ৰশ্ন মচক"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"প্ৰশ্ন দাখিল কৰক"</string>
@@ -1468,7 +1472,7 @@
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্ৰণ কৰিবলৈ দুবাৰ টিপক"</string>
     <string name="gadget_host_error_inflating" msgid="2449961590495198720">"ৱিজেট যোগ কৰিব পৰা নগ\'ল।"</string>
     <string name="ime_action_go" msgid="5536744546326495436">"যাওক"</string>
-    <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+    <string name="ime_action_search" msgid="4501435960587287668">"সন্ধান কৰক"</string>
     <string name="ime_action_send" msgid="8456843745664334138">"পঠিয়াওক"</string>
     <string name="ime_action_next" msgid="4169702997635728543">"পৰৱৰ্তী"</string>
     <string name="ime_action_done" msgid="6299921014822891569">"সম্পন্ন হ’ল"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শ্বৰ্টকাটটো অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটাম ৩ ছেকেণ্ডৰ বাবে হেঁচি ধৰি ৰাখিলে এটা সাধ্য সুবিধা আৰম্ভ হ’ব।"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"সাধ্য সুবিধাসমূহৰ বাবে শ্বৰ্টকাট অন কৰিবনে?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে সাধ্য-সুবিধাসমূহ অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nবর্তমানৰ সুবিধাসমূহ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nআপুনি ছেটিংসমূহ &gt; সাধ্য-সুবিধাত কিছুমান নিৰ্দিষ্ট সুবিধা সলনি কৰিব পাৰে।"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>ৰ শ্বৰ্টকাট অন কৰিবনে?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে এটা সাধ্য- সুবিধা <xliff:g id="SERVICE">%1$s</xliff:g> অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nআপুনি ছেটিংসমূহ &gt; সাধ্য-সুবিধাসমূহত এই শ্বৰ্টকাটটো অন্য এটা সুবিধালৈ সলনি কৰিব পাৰে।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"অন কৰক"</string>
@@ -1973,7 +1978,7 @@
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"প্ৰস্তাৱিত"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"সকলো ভাষা"</string>
     <string name="region_picker_section_all" msgid="756441309928774155">"সকলো অঞ্চল"</string>
-    <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+    <string name="locale_search_menu" msgid="6258090710176422934">"সন্ধান কৰক"</string>
     <string name="app_suspended_title" msgid="888873445010322650">"এপটো নাই"</string>
     <string name="app_suspended_default_message" msgid="6451215678552004172">"এই মুহূৰ্তত <xliff:g id="APP_NAME_0">%1$s</xliff:g> উপলব্ধ নহয়। ইয়াক <xliff:g id="APP_NAME_1">%2$s</xliff:g>এ পৰিচালনা কৰে।"</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"অধিক জানক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 00145ba..24ea7fc 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Davam etmək üçün barmaq izi və ya ekran kilidinizdən istifadə edin"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmaq izi ikonası"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Üz ilə kiliddən çıxarma"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Üz ilə kiliddən çıxarma problemi"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davam etmək üçün üz və ya ekran kilidinizdən istifadə edin"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Üz işarəsi"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"sinx ayarlarını oxu"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tətbiqə hesablar üçün sinxronizasiya nizamlarını oxuma icazəsi verir. Məsələn, bu Şəxslər tətbiqinin sinxronizə olunub-olunmadığını təyin edə bilər."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Qısayol aktiv olduqda, hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası başladılacaq."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Əlçatımlılıq funksiyaları üçün qısayol aktiv edilsin?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyaları aktiv olur. Cihazınızın işləmə qaydasını dəyişə bilər.\n\nCari funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAyarlar və Əlçatımlılıq bölməsində seçilmiş funksiyaları dəyişə bilərsiniz."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> qısayolu aktiv edilsin?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyası olan <xliff:g id="SERVICE">%1$s</xliff:g> aktiv olur. Cihazınızın işləmə qaydasını dəyişə bilər.\n\nAyarlar və Əlçatımlılıq bölməsində bu qısayolu başqa bir funksiyaya dəyişə bilərsiniz."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktiv edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 65bfec1..80b3a3a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -612,6 +612,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Koristite otisak prsta ili zaključavanje ekrana da biste nastavili"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem sa otključavanje licem"</string>
@@ -664,6 +666,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da biste nastavili"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje podešavanja sinhronizacije"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Dozvoljava aplikaciji da čita podešavanja sinhronizacije za nalog. Na primer, ovako može da se utvrdi da li je aplikacija Ljudi sinhronizovana sa nalogom."</string>
@@ -1714,7 +1718,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite da uključite prečicu za funkcije pristupačnosti?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako zadržite oba tastera za jačinu zvuka par sekundi, uključiće se funkcije pristupačnosti. To može da promeni način rada uređaja.\n\nPostojeće funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nMožete da promenite izabrane funkcije u odeljku Podešavanja &gt; Pristupačnost."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite da uključite prečicu za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako zadržite oba tastera za jačinu zvuka par sekundi, uključuje se <xliff:g id="SERVICE">%1$s</xliff:g>, funkcija pristupačnosti. To može da promeni način rada uređaja.\n\nMožete da promenite funkciju na koju se odnosi ova prečica u odeljku Podešavanja &gt; Pristupačnost."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index a4726cf..8f74705 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Каб працягнуць, скарыстайце адбітак пальца ці сродак разблакіроўкі экрана"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок адбіткаў пальцаў"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Распазнаванне твару"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Праблема з распазнаваннем твару"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Каб працягнуць, скарыстайце распазнаванне твару ці сродак разблакіроўкі экрана"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Значок твару"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"чытаць параметры сінхранізацыі"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дазваляе прыкладанням чытаць параметры сінхранізацыі для ўліковага запісу. Напрыклад, яны могуць вызначыць, цi сiнхранiзавана з улiковым запiсам прыкладанне \"Кантакты\"."</string>
@@ -972,7 +976,7 @@
     <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"Вобласць узора."</string>
     <string name="keyguard_accessibility_slide_area" msgid="4331399051142520176">"Вобласць слайда."</string>
     <string name="password_keyboard_label_symbol_key" msgid="2716255580853511949">"123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"ABC"</string>
+    <string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"АБВ"</string>
     <string name="password_keyboard_label_alt_key" msgid="8528261816395508841">"Alt"</string>
     <string name="granularity_label_character" msgid="8903387663153706317">"Знак"</string>
     <string name="granularity_label_word" msgid="3686589158760620518">"слова"</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Калі хуткі доступ уключаны, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб запусціць функцыю спецыяльных магчымасцей."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Уключыць хуткі доступ да спецыяльных магчымасцей?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Утрымліванне націснутымі абедзвюх клавіш гучнасці на працягу некалькіх секунд уключае спецыяльныя магчымасці. У выніку ваша прылада можа пачаць працаваць па-іншаму.\n\nБягучыя функцыі:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nВыбраныя функцыі можна змяніць у меню \"Налады &gt; Спецыяльныя магчымасці\"."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Уключыць хуткі доступ да сэрвісу \"<xliff:g id="SERVICE">%1$s</xliff:g>\"?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Утрымліванне націснутымі абедзвюх клавіш гучнасці на працягу некалькіх секунд уключае службу \"<xliff:g id="SERVICE">%1$s</xliff:g>\", якая з\'яўляецца спецыяльнай магчымасцю. У выніку ваша прылада можа пачаць працаваць па-іншаму.\n\nВы можаце задаць гэта спалучэнне клавіш для іншай функцыі ў меню \"Налады &gt; Спецыяльныя магчымасці\"."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Уключыць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c74f488..01b2379 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Използвайте отпечатъка си или опцията за заключване на екрана, за да продължите"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатък"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Отключване с лице"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем с отключването с лице"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Използвайте лицето си или опцията за заключване на екрана, за да продължите"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Икона на лице"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"четене на настройките за синхронизиране"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Разрешава на приложението да чете настройките за синхронизиране на профил. Например това може да определи дали приложението Хора е синхронизирано с даден профил."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за силата на звука и ги задържите за 3 секунди."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Искате ли да включите прекия път за функциите за достъпност?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Натиснете двата бутона за силата на звука и ги задръжте за няколко секунди, за да включите функциите за достъпност. Това може да промени начина, по който работи устройството ви.\n\nТекущи функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМожете да промените избраните функции от „Настройки“ &gt; „Достъпност“."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Искате ли да включите прекия път за <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Натиснете двата бутона за силата на звука и ги задръжте за няколко секунди, за да включите функцията за достъпност <xliff:g id="SERVICE">%1$s</xliff:g>. Това може да промени начина, по който работи устройството ви.\n\nМожете да зададете друга функция за този пряк път от „Настройки“ &gt; „Достъпност“."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Включване"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 584fb61..5253e41 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"চালিয়ে যেতে আপনার আঙুলের ছাপ বা স্ক্রিন লক ব্য়বহার করুন"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেস আনলক"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"\'ফেস আনলক\' ফিচার ব্যবহার করার ক্ষেত্রে হওয়া সমস্যা"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"চালিয়ে যেতে আপনার ফেস বা স্ক্রিন লক ব্যবহার করুন"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ফেস আইকন"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"সিঙ্ক সেটিংস পড়ে"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"অ্যাপ্লিকেশানটিকে একটি অ্যাকাউন্টের জন্য সিঙ্ক সেটিংস পড়ার অনুমতি দেয়৷ উদাহরণস্বরূপ, \'পিপল\' অ্যাপ্লিকেশানটি কোনো অ্যাকাউন্টের সাথে সিঙ্ক করা আছে কিনা তা নির্ধারণ করতে পারে৷"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শর্টকাট চালু করা থাকাকালীন দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি ফিচার চালু হবে।"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"অ্যাক্সেসিবিলিটি ফিচারের শর্টকাট বন্ধ করতে চান?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে অ্যাক্সেসিবিলিটি ফিচার চালু হয়ে যাবে। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nবর্তমান ফিচার:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nসেটিংস &gt; অ্যাক্সেসিবিলিটি বিকল্প থেকে আপনি বাছাই করা ফিচার পরিবর্তন করতে পারবেন।"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> শর্টকাট চালু করতে চান?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে <xliff:g id="SERVICE">%1$s</xliff:g> চালু হয়ে যাবে। এটি একটি অ্যাক্সেসিবিলিটি ফিচার। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nসেটিংস &gt; অ্যাক্সেসিবিলিটি থেকে আপনি এই শর্টকাট পরিবর্তন করতে পারবেন।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"চালু করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index b6497ab..2995f3c 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -612,6 +612,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Koristite otisak prsta ili zaključavanje ekrana da nastavite"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona za otisak prsta"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem s otključavanjem licem"</string>
@@ -664,6 +666,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da nastavite"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje postavki za sinhroniziranje"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Omogućava aplikaciji čitanje postavki sinhroniziranja za račun. Naprimjer, ovim se može utvrditi da li je aplikacija People sinhronizirana sa računom."</string>
@@ -1714,7 +1718,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Uključiti prečicu za funkcije pristupačnosti?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkcije pristupačnosti. Ovo može uticati na način rada uređaja.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane funkcije možete promijeniti u odjeljku Postavke &gt; Pristupačnost."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Uključiti prečicu za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkciju pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Ovo može promijeniti način rada uređaja.\n\nOvu prečicu možete zamijeniti drugom funkcijom u odjeljku Postavke &gt; Pristupačnost."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 507fecd..a182585 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilitza l\'empremta digital o el bloqueig de pantalla per continuar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona d\'empremta digital"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueig facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema amb Desbloqueig facial"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilitza la cara o el bloqueig de pantalla per continuar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Icona facial"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"llegir la configuració de sincronització"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Contactes estigui sincronitzada amb un compte."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si la drecera està activada, prem els dos botons de volum durant 3 segons per iniciar una funció d\'accessibilitat."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vols desactivar la drecera de les funcions d\'accessibilitat?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si mantens premudes les dues tecles de volum durant uns segons, s\'activaran les funcions d\'accessibilitat. Això podria canviar el funcionament del teu dispositiu.\n\nFuncions actuals:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPots canviar les funcions seleccionades a Configuració &gt; Accessibilitat."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vols activar la drecera de <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si mantens premudes les dues tecles de volum durant uns segons, la funció d\'accessibilitat <xliff:g id="SERVICE">%1$s</xliff:g> s\'activarà. Això podria canviar el funcionament del teu dispositiu.\n\nPots canviar la funció d\'aquesta drecera a Configuració &gt; Accessibilitat."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activa"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2ca6c52..75528bb 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Pokračujte ověřením pomocí otisku prstu nebo zámku obrazovky"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otisku prstů"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odemknutí obličejem"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problém s odemykáním obličejem"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte ověřením pomocí obličeje nebo zámku obrazovky"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona obličeje"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čtení nastavení synchronizace"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Umožňuje aplikaci číst nastavení synchronizace v účtu. Může například určit, zda je s účtem synchronizována aplikace Lidé."</string>
@@ -1370,9 +1374,9 @@
     <string name="sms_control_message" msgid="6574313876316388239">"Aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;odesílá velký počet SMS zpráv. Chcete aplikaci povolit, aby zprávy odesílala i nadále?"</string>
     <string name="sms_control_yes" msgid="4858845109269524622">"Povolit"</string>
     <string name="sms_control_no" msgid="4845717880040355570">"Odmítnout"</string>
-    <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chce odeslat zprávu na adresu &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
+    <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chce odeslat zprávu na číslo &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
     <string name="sms_short_code_details" msgid="2723725738333388351">"Tato akce "<b>"může vést k naúčtování poplatků"</b>" na váš účet u mobilního operátora."</string>
-    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Tato akce povede k naúčtování poplatku na váš účet u mobilního operátora."</b></string>
+    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Tato akce může vést k naúčtování ceny služby třetí strany na vrub vašeho účtu u mobilního operátora."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Odeslat"</string>
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Zrušit"</string>
     <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Zapamatovat moji volbu"</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Zapnout zkratku funkcí pro usnadnění přístupu?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Podržením obou tlačítek hlasitosti po dobu několika sekund zapnete funkce pro usnadnění přístupu. Tato funkce může změnit fungování zařízení.\n\nAktuální funkce:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVybrané funkce můžete změnit v Nastavení &gt; Přístupnost."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Zapnout zkratku služby <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Podržením obou tlačítek hlasitosti po dobu několika sekund zapnete funkci pro usnadnění přístupu <xliff:g id="SERVICE">%1$s</xliff:g>. Tato funkce může změnit fungování zařízení.\n\nZkratku můžete nastavit na jinou funkci v Nastavení &gt; Přístupnost."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Zapnout"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0c26400..f504cc7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Brug dit fingeraftryk eller din skærmlås for at fortsætte"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeraftryk"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansigtslås"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Der er et problem med Ansigtslås"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Brug din ansigts- eller skærmlås for at fortsætte"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ansigt"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"læse indstillinger for synkronisering"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tillader, at appen kan læse synkroniseringsindstillingerne for en konto. Denne tilladelse kan f.eks. fastslå, om appen Personer er synkroniseret med en konto."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når genvejen er aktiveret, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vil du aktivere genvejen til hjælpefunktioner?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hvis du holder begge lydstyrkeknapperne nede i et par sekunder, aktiveres hjælpefunktionerne. Det kan ændre på, hvordan din enhed fungerer.\n\nAktuelle funktioner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan ændre de valgte funktioner i Indstillinger &gt; Hjælpefunktioner."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vil du aktivere <xliff:g id="SERVICE">%1$s</xliff:g>-genvejen?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hvis du holder begge lydstyrkeknapperne nede i et par sekunder, aktiveres hjælpefunktionen <xliff:g id="SERVICE">%1$s</xliff:g>. Det kan ændre på, hvordan din enhed fungerer.\n\nDu kan ændre denne genvej til en anden funktion i Indstillinger &gt; Hjælpefunktioner."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivér"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5245437..831a66b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Verwende deinen Fingerabdruck oder deine Display-Entsperrmethode, um fortzufahren"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerabdruck-Symbol"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Entsperrung per Gesichtserkennung"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem bei der Entsperrung per Gesichtserkennung"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Verwende die Gesichtserkennung oder deine Display-Entsperrmethode, um fortzufahren"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Gesichtssymbol"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"Synchronisierungseinstellungen lesen"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Verknüpfung für Bedienungshilfen aktivieren?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Wenn du beide Lautstärketasten einige Sekunden lang gedrückt hältst, aktivierst du die Bedienungshilfen. Dadurch kann sich die Funktionsweise deines Geräts ändern.\n\nAktuelle Funktionen:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kannst ausgewählte Funktionen unter \"Einstellungen\" &gt; \"Bedienungshilfen\" ändern."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Verknüpfung für <xliff:g id="SERVICE">%1$s</xliff:g> aktivieren?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Wenn du beide Lautstärketasten einige Sekunden lang gedrückt hältst, aktivierst du die Bedienungshilfe \"<xliff:g id="SERVICE">%1$s</xliff:g>\". Dadurch kann sich die Funktionsweise deines Geräts ändern.\n\nUnter \"Einstellungen &gt; \"Bedienungshilfen\" kannst du dieser Verknüpfung eine andere Funktion zuweisen."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivieren"</string>
@@ -1938,7 +1943,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-el/strings.xml b/core/res/res/values-el/strings.xml
index 6fe7d63..beffc46 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Χρησιμοποιήστε το δακτυλικό σας αποτύπωμα ή το κλείδωμα οθόνης για να συνεχίσετε"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ξεκλείδωμα με το πρόσωπο"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Πρόβλημα με το Ξεκλείδωμα με το πρόσωπο"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Χρησιμοποιήστε το πρόσωπό σας ή το κλείδωμα οθόνης για συνέχεια"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Εικ. προσ."</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"διαβάζει τις ρυθμίσεις συγχρονισμού"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ενεργοποίηση συντόμευσης για λειτουργίες προσβασιμότητας;"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Για να ενεργοποιήσετε τις λειτουργίες προσβασιμότητας, πατήστε παρατεταμένα τα δύο πλήκτρα έντασης για μερικά δευτερόλεπτα. Αυτό ενδέχεται να αλλάξει τον τρόπο λειτουργίας της συσκευής σας.\n\nΤρέχουσες λειτουργίες:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nΜπορείτε να αλλάξετε τις επιλεγμένες λειτουργίες στις Ρυθμίσεις &gt; Προσβασιμότητα."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ενεργοποίηση συντόμευσης <xliff:g id="SERVICE">%1$s</xliff:g>;"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Μπορείτε να ενεργοποιήσετε τη λειτουργία <xliff:g id="SERVICE">%1$s</xliff:g>, η οποία είναι μία από τις λειτουργίες προσβασιμότητας, πατώντας παρατεταμένα ταυτόχρονα τα δύο πλήκτρα έντασης ήχου για μερικά δευτερόλεπτα. Αυτό ενδέχεται να αλλάξει τον τρόπο λειτουργίας της συσκευής σας.\n\nΜπορείτε να αλλάξετε αυτή τη συντόμευση σε μια άλλη λειτουργία στις Ρυθμίσεις &gt; Προσβασιμότητα."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ενεργοποίηση"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 13725de..0b02d69 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings &gt; Accessibility."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings &gt; Accessibility."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9205763..c9167614 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings &gt; Accessibility."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings &gt; Accessibility."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 45709f0..34eeff4 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings &gt; Accessibility."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings &gt; Accessibility."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 8749d05..ef7924e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings &gt; Accessibility."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings &gt; Accessibility."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 996a332..7aa9f44 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎Use your fingerprint or screen lock to continue‎‏‎‎‏‎"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎Something went wrong. Try again.‎‏‎‎‏‎"</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎Fingerprint icon‎‏‎‎‏‎"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‎‎Face Unlock‎‏‎‎‏‎"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎Issue with Face Unlock‎‏‎‎‏‎"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎Use your face or screen lock to continue‎‏‎‎‏‎"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‎Something went wrong. Try again.‎‏‎‎‏‎"</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎Face icon‎‏‎‎‏‎"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎read sync settings‎‏‎‎‏‎"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‎‎Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account.‎‏‎‎‏‎"</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎Turn on shortcut for accessibility features?‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Current features:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="SERVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You can change selected features in Settings &gt; Accessibility.‎‏‎‎‏‎"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎	• ‎‏‎‎‏‏‎<xliff:g id="SERVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‎‎ • ‎‏‎‎‏‏‎<xliff:g id="SERVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎Turn on ‎‏‎‎‏‏‎<xliff:g id="SERVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ shortcut?‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‏‎Holding down both volume keys for a few seconds turns on ‎‏‎‎‏‏‎<xliff:g id="SERVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎, an accessibility feature. This may change how your device works.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You can change this shortcut to another feature in Settings &gt; Accessibility.‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎Turn on‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 569cfcf..3de374d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella dactilar o bloqueo de pantalla para continuar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella dactilar"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con el Desbloqueo facial"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu rostro o bloqueo de pantalla para continuar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ícono cara"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cuando la combinación de teclas está activada, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar la combinación de teclas para las funciones de accesibilidad?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si mantienes presionadas las dos teclas de volumen durante unos segundos, se activarán las funciones de accesibilidad. Esto puede cambiar el funcionamiento de tu dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Configuración &gt; Accesibilidad."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"¿Quieres activar el acceso directo de <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si mantienes presionadas ambas teclas de volumen durante unos segundos, se activará la función de accesibilidad <xliff:g id="SERVICE">%1$s</xliff:g>. Esto podría cambiar la forma en que funciona tu dispositivo.\n\nPuedes cambiar este acceso directo a otra función en Configuración &gt; Accesibilidad."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 716b2c8..68e90f1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella digital o tu bloqueo de pantalla para continuar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Se ha producido un error. Inténtalo de nuevo."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icono de huella digital"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con Desbloqueo facial"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu cara o tu bloqueo de pantalla para continuar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Se ha producido un error. Inténtalo de nuevo."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Icono cara"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar el acceso directo a las funciones de accesibilidad?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Al mantener pulsadas las dos teclas de volumen durante unos segundos, se activan las funciones de accesibilidad, que pueden cambiar el funcionamiento del dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Ajustes &gt; Accesibilidad."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"¿Quieres activar el acceso directo a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Al mantener pulsadas ambas teclas de volumen durante unos segundos se activa <xliff:g id="SERVICE">%1$s</xliff:g>, una función de accesibilidad. Esta función puede modificar el funcionamiento del dispositivo.\n\nPuedes asignar este acceso directo a otra función en Ajustes &gt; Accesibilidad."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 6153a83..e549d45 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jätkamiseks kasutage oma sõrmejälge või ekraanilukku"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Näoga avamine"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem funktsiooniga Näoga avamine"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jätkamiseks kasutage oma nägu või ekraanilukku"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Näoikoon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"loe sünkroonimisseadeid"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Võimaldab rakendusel lugeda konto sünkroonimisseadeid. Näiteks võib see määrata, kas rakendus Inimesed on kontoga sünkroonitud."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Kas lülitada juurdepääsufunktsioonide otsetee sisse?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hoidke juurdepääsufunktsioonide sisselülitamiseks mõlemat helitugevuse klahvi mõni sekund all. See võib teie seadme tööviisi muuta.\n\nPraegused funktsioonid:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nValitud funktsioone saab muuta jaotises Seaded &gt; Juurdepääsetavus."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Kas lülitada teenuse <xliff:g id="SERVICE">%1$s</xliff:g> otsetee sisse?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Kui hoiate mõlemat helitugevuse klahvi mõni sekund all, lülitatakse juurdepääsufunktsioon <xliff:g id="SERVICE">%1$s</xliff:g> sisse. See võib teie seadme tööviisi muuta.\n\nSelle otsetee saab asendada muu otseteega jaotises Seaded &gt; Juurdepääsetavus."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Lülita sisse"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index a56d19a..01d191d 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aurrera egiteko, erabili hatz-marka edo pantailaren blokeoa"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Aurpegi bidez desblokeatzeko eginbidea"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arazoak ditugu aurpegi bidez desblokeatzeko eginbidearekin"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aurrera egiteko, erabili aurpegia edo pantailaren blokeoa"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Aurpegiaren ikonoa"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"irakurri sinkronizazio-ezarpenak"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Kontu baten sinkronizazio-ezarpenak irakurtzeko baimena ematen die aplikazioei. Adibidez, Jendea aplikazioa konturen batekin sinkronizatuta dagoen zehatz dezake."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erabilerraztasun-eginbideetarako lasterbidea aktibatu nahi duzu?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Eduki sakatuta bolumen-botoiak segundo batzuez erabilerraztasun-eginbideak aktibatzeko. Hori eginez gero, baliteke zure mugikorraren funtzionamendua aldatzea.\n\nEginbideak:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nHautatutako eginbideak aldatzeko, joan Ezarpenak &gt; Erabilerraztasuna atalera."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> zerbitzuaren lasterbidea aktibatu nahi duzu?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Eduki sakatuta bolumen-botoiak segundo batzuez <xliff:g id="SERVICE">%1$s</xliff:g> izeneko erabilerraztasun-eginbidea aktibatzeko. Honen bidez, baliteke zure mugikorraren funtzionamendua aldatzea.\n\nLasterbide hau beste eginbide batengatik aldatzeko, joan Ezarpenak &gt; Erabilerraztasuna atalera."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktibatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 1c49d95..393382a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"برای ادامه، از اثر انگشت یا قفل صفحه استفاده کنید"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"نماد اثر انگشت"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"قفل‌گشایی با چهره"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"مشکل در «قفل‌گشایی با چهره»"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"برای ادامه، از تشخیص چهره یا قفل صفحه استفاده کنید"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"نماد چهره"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"خواندن تنظیمات همگام‌سازی"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"به برنامه اجازه می‌دهد تنظیمات را برای یک حساب بخواند. به‌عنوان مثال، این ویژگی می‌تواند تعیین کند آیا حساب «افراد» شما با یک حساب همگام‌سازی شده است."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"وقتی میان‌بر روشن باشد، با فشار دادن هردو دکمه صدا به‌مدت ۳ ثانیه ویژگی دسترس‌پذیری فعال می‌شود."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"میان‌بر برای ویژگی‌های دسترس‌پذیری روشن شود؟"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"با پایین نگه داشتن هردو کلید میزان صدا به‌مدت چند ثانیه، ویژگی‌های دسترس‌پذیری روشن می‌شود. با این کار نحوه عملکرد دستگاهتان تغییر می‌کند.\n\nویژگی‌های فعلی:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nمی‌توانید ویژگی‌های انتخابی را در «تنظیمات &gt; دسترس‌پذیری» تغییر دهید."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"میان‌بر <xliff:g id="SERVICE">%1$s</xliff:g> روشن شود؟"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"با پایین نگه داشتن هردو کلید میزان صدا به‌مدت چند ثانیه، <xliff:g id="SERVICE">%1$s</xliff:g> (یکی از ویژگی‌های دسترس‌پذیری) روشن می‌شود. با این کار نحوه عملکرد دستگاهتان تغییر می‌کند.\n\nمی‌توانید در «تنظیمات &gt; دسترس‌پذیری»،‌این میان‌بر را به ویژگی دیگری تغییر دهید."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"روشن شود"</string>
@@ -1950,7 +1955,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-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5c7b4a7..4ce9a323 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jatka sormenjäljen tai näytön lukituksen avulla"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sormenjälkikuvake"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Kasvojentunnistusavaus"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Face Unlockiin liittyvä ongelma"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jatka kasvojentunnistuksen tai näytön lukituksen avulla"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Kasvokuvake"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lue synkronointiasetuksia"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Antaa sovelluksen lukea tilien synkronointiasetuksia. Sovellus voi esimerkiksi määrittää, onko Henkilöt-sovellus synkronoitu tilin kanssa."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Laitetaanko esteettömyysominaisuuksien pikavalinta päälle?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Molempien äänenvoimakkuuspainikkeiden painaminen muutaman sekunnin ajan laittaa esteettömyysominaisuudet päälle. Tämä voi muuttaa laitteesi toimintaa.\n\nNykyiset ominaisuudet:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVoit muuttaa valittuja ominaisuuksia kohdassa Asetukset &gt; Esteettömyys."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Laitetaanko pikavalinta (<xliff:g id="SERVICE">%1$s</xliff:g>) päälle?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Molempien äänenvoimakkuuspainikkeiden pitkään painaminen laittaa päälle esteettömyysominaisuuden <xliff:g id="SERVICE">%1$s</xliff:g>. Tämä voi muuttaa laitteesi toimintaa.\n\nVoit muuttaa tätä pikanäppäintä kohdassa Asetukset &gt; Esteettömyys."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Laita päälle"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 83a9ac2..9b16ba7 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilisez votre empreinte digitale ou le verrouillage de l\'écran pour continuer"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème avec la fonctionnalité de déverrouillage par reconnaissance faciale"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez votre visage ou le verrouillage de l\'écran pour continuer"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activer le raccourci pour les fonctionnalités d\'accessibilité?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si vous maintenez enfoncées les deux touches de volume pendant quelques secondes, vous activez les fonctionnalités d\'accessibilité. Cela peut modifier le fonctionnement de votre appareil.\n\nFonctionnalités actuellement utilisées :\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPour les modifier, sélectionnez Paramètres &gt; Accessibilité."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activer le raccourci pour <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si vous maintenez enfoncées les deux touches de volume pendant quelques secondes, vous activez la fonctionnalité d\'accessibilité <xliff:g id="SERVICE">%1$s</xliff:g>. Cela peut modifier le fonctionnement de votre appareil.\n\nPour attribuer ce raccourci à une autre fonctionnalité, sélectionnez Paramètres &gt; Accessibilité."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 4fec45b..08394ad 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilisez votre empreinte digitale ou le verrouillage de l\'écran pour continuer"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème lié au déverrouillage par reconnaissance faciale"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez la reconnaissance faciale ou le verrouillage de l\'écran pour continuer"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour démarrer une fonctionnalité d\'accessibilité."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activer le raccourci pour accéder aux fonctionnalités d\'accessibilité ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si vous appuyez sur les deux touches de volume pendant quelques secondes, vous activez des fonctionnalités d\'accessibilité. Cela peut affecter le fonctionnement de votre appareil.\n\nFonctionnalités actuellement utilisées :\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPour les modifier, accédez à Paramètres &gt; Accessibilité."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activer le raccourci <xliff:g id="SERVICE">%1$s</xliff:g> ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si vous appuyez sur les deux touches de volume pendant quelques secondes, vous activez la fonctionnalité d\'accessibilité <xliff:g id="SERVICE">%1$s</xliff:g>. Cela peut affecter le fonctionnement de votre appareil.\n\nPour attribuer ce raccourci à une autre fonctionnalité, accédez à Paramètres &gt; Accessibilité."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activer"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index cdbe604..47ca329 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Para continuar, utiliza a impresión dixital ou o bloqueo de pantalla"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona de impresión dixital"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Produciuse un problema co desbloqueo facial"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Para continuar, utiliza o desbloqueo facial ou a credencial do dispositivo"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Icona cara"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler a configuración de vinculación"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite á aplicación ler a configuración de vinculación dunha conta. Por exemplo, esta acción pode determinar se a aplicación Contactos se vincula cunha conta."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Queres activar as funcións de accesibilidade?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ao manter as dúas teclas de volume premidas durante uns segundos actívanse as funcións de accesibilidade. Esta acción pode cambiar o funcionamento do dispositivo.\n\nFuncións activadas actualmente:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPodes cambiar as funcións seleccionadas en Configuración &gt; Accesibilidade."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Queres activar o atallo a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ao manter as dúas teclas de volume premidas durante uns segundos actívase <xliff:g id="SERVICE">%1$s</xliff:g>, unha función de accesibilidade. Esta acción pode cambiar o funcionamento do dispositivo.\n\nPodes cambiar o uso deste atallo para outra función en Configuración &gt; Accesibilidade."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 710e943..133d144 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"પીઅરે TTY મોડ HCO ની વિનંતી કરી"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"પીઅરે TTY મોડ VCO ની વિનંતી કરી"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"પીઅરે TTY મોડ બંધ કરવાની વિનંતી કરી"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"વૉઇસ"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ડેટા"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ફેક્સ"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -306,7 +306,7 @@
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"તમારા સંપર્કોને ઍક્સેસ કરવાની"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"સ્થાન"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string>
-    <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+    <string name="permgrouplab_calendar" msgid="6426860926123033230">"કૅલેન્ડર"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS સંદેશા મોકલવાની અને જોવાની"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ચાલુ રાખવા માટે તમારા ફિંગરપ્રિન્ટ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ફિંગરપ્રિન્ટ આયકન"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ફેસ અનલૉક"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ફેસ અનલૉકની સુવિધામાં સમસ્યા"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ચાલુ રાખવા માટે તમારા ફેસ લૉક અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"સિંક સેટિંગ વાંચો"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ સિંક થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
@@ -848,7 +852,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"અન્ય"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"કસ્ટમ"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"કસ્ટમ"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"આસિસ્ટંટ"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"ભાઈ"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"બાળક"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"ઘરેલું ભાગીદાર"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ઍક્સેસિબિલિટી સુવિધાઓ માટે શૉર્ટકટ ચાલુ કરીએ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"બન્ને વૉલ્યૂમ કીને થોડી સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધાઓ ચાલુ થઈ જાય છે. આનાથી તમારા ડિવાઇસની કામ કરવાની રીત બદલાઈ શકે છે.\n\nવર્તમાન સુવિધાઓ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nતમે સેટિંગ &gt; ઍક્સેસિબિલિટીમાં જઈને પસંદ કરેલી સુવિધાઓને બદલી શકો છો."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> શૉર્ટકટ ચાલુ કરીએ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"બન્ને વૉલ્યૂમ કીને થોડી સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા એવી <xliff:g id="SERVICE">%1$s</xliff:g> ચાલુ થઈ જાય છે. આનાથી તમારા ડિવાઇસની કામ કરવાની રીત બદલાઈ શકે છે.\n\nતમે સેટિંગ &gt; ઍક્સેસિબિલિટીમાં જઈને આ શૉર્ટકટને બીજી સુવિધામાં બદલી શકો છો."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ચાલુ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b5261e0..c678650 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -326,7 +326,7 @@
     <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>
+    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विंडो का कॉन्टेंट वापस पाएं"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"उस विंडो की सामग्री की जाँच करें, जिसका आप इस्तेमाल कर रहे हैं."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"छूकर, किसी चीज़ से जुड़ी जानकारी सुनने की सुविधा चालू करें"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"जिन चीज़ों पर आप टैप करेंगे उन्हें ज़ोर से बोला जाएगा और स्क्रीन को जेस्चर के ज़रिए एक्सप्लोर किया जा सकेगा."</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"जारी रखने के लिए, फ़िंगरप्रिंट या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फ़िंगरप्रिंट आइकॉन"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फ़ेस अनलॉक"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फ़ेस अनलॉक से जुड़ी समस्या"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी रखने के लिए, अपना चेहरा दिखाकर या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"चेहरे का आइकॉन"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"समन्वयन सेटिंग पढ़ें"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ऐप्स  को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह तय किया जा सकता है कि लोग ऐप्स  किसी खाते के साथ समन्‍वयित है या नहीं."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट के चालू होने पर, दाेनाें वॉल्यूम बटन (आवाज़ कम या ज़्यादा करने वाले बटन) को तीन सेकंड तक दबाने से, सुलभता सुविधा शुरू हाे जाएगी."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"क्या आप सुलभता सुविधाओं के लिए शॉर्टकट चालू करना चाहते हैं?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"आवाज़ कम और ज़्यादा करने वाले दोनों बटन को कुछ सेकंड तक दबाकर रखने से सुलभता सुविधाएं चालू हो जाती हैं. ऐसा करने से आपके डिवाइस के काम करने के तरीके में बदलाव हो सकता है.\n\nमौजूदा सुविधाएं:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nआप सेटिंग और सुलभता में जाकर चुनी हुई सुविधाएं बदल सकते हैं."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"क्या आप <xliff:g id="SERVICE">%1$s</xliff:g> शॉर्टकट चालू करना चाहते हैं?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"आवाज़ कम और ज़्यादा करने वाले दोनों बटन को कुछ सेकंड तक दबाकर रखने से <xliff:g id="SERVICE">%1$s</xliff:g> चालू हो जाती है, जो एक सुलभता सुविधा है. ऐसा करने से आपके डिवाइस के काम करने के तरीके में बदलाव हो सकता है.\n\nआप सेटिंग और सुलभता में जाकर इस शॉर्टकट को किसी दूसरी सुविधा के लिए बदल सकते हैं."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"चालू करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 281cf85..35cd2f5 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -612,6 +612,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Za nastavak se identificirajte otiskom prsta ili vjerodajnicom zaključavanja zaslona"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Poteškoće s otključavanjem licem"</string>
@@ -664,6 +666,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nastavak se identificirajte licem ili vjerodajnicom zaključavanja zaslona"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje postavki sinkronizacije"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Aplikaciji omogućuje čitanje postavki sinkronizacije za račun. Time se, primjerice, može utvrditi je li aplikacija Osobe sinkronizirana s računom."</string>
@@ -1714,7 +1718,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad je taj prečac uključen, pritiskom na obje tipke za glasnoću na tri sekunde pokrenut će se značajka pristupačnosti."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite li uključiti prečac za značajke pristupačnosti?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Značajke pristupačnosti uključuju se ako na nekoliko sekundi pritisnete obje tipke za glasnoću. Time se može promijeniti način na koji vaš uređaj radi.\n\nTrenutačne značajke:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane značajke možete promijeniti u odjeljku Postavke &gt; Pristupačnost."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite li uključiti prečac za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako na nekoliko sekundi pritisnete obje tipke za glasnoću, uključuje se značajka pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Time se može promijeniti način na koji vaš uređaj radi.\n\nZnačajku na koju se taj prečac odnosi možete promijeniti u odjeljku Postavke &gt; Pristupačnost."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9e0232d..2e383ec 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"A folytatás ujjlenyomattal vagy a képernyőzár feloldásával lehetséges"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ujjlenyomat ikon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Arcalapú feloldás"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arcalapú feloldással kapcsolatos problémák"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"A folytatás arcalapú feloldással vagy a képernyőzár feloldásával lehetséges"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Arcikon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"szinkronizálási beállítások olvasása"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lehetővé teszi az alkalmazás számára egy fiók szinkronizálási beállításainak beolvasását. Például ellenőrizheti, hogy a Személyek alkalmazás szinkronizálva van-e egy fiókkal."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ha a gyorsparancs aktív, akkor a két hangerőgomb három másodpercig tartó együttes lenyomásával kisegítő funkciót indíthat el."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Bekapcsol gyorsparancsot a kisegítő lehetőségekhez?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"A kisegítő lehetőségek bekapcsolásához tartsa nyomva néhány másodpercig mindkét hangerőgombot. Ez hatással lehet az eszköz működésére.\n\nJelenlegi funkciók:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nA kiválasztott funkciókat a Beállítások &gt; Kisegítő lehetőségek pontban módosíthatja."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Bekapcsolja a(z) <xliff:g id="SERVICE">%1$s</xliff:g> szolgáltatás gyorsparancsát?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"A(z) <xliff:g id="SERVICE">%1$s</xliff:g> kisegítő lehetőség bekapcsolásához tartsa nyomva néhány másodpercig mindkét hangerőgombot. Ez hatással lehet az eszköz működésére.\n\nEzt a gyorsparancsot a Beállítások &gt; Kisegítő lehetőségek pontban módosíthatja másik funkció használatára."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Bekapcsolom"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 6fdf577..f4c0316 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Շարունակելու համար օգտագործեք ձեր մատնահետքը կամ էկրանի կողպումը"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Մատնահետքի պատկերակ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Դեմքով ապակողպում"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Դեմքով ապակողպման հետ կապված խնդիր"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Շարունակելու համար օգտագործեք ձեր դեմքը կամ էկրանի կողպումը"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"կարդալ համաժամացման կարգավորումները"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ՝ այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է:"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Միացնե՞լ հատուկ գործառույթների դյուրանցումը"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ձայնի կարգավորման երկու կոճակները մի քանի վայրկյան սեղմած պահելով կմիացնեք հատուկ գործառույթները։ Դրա արդյունքում սարքի աշխատաեղանակը կարող է փոխվել։\n\nԸնթացիկ գործառույթներ՝\n<xliff:g id="SERVICE">%1$s</xliff:g>\nԸնտրված գործառույթները փոխելու համար անցեք Կարգավորումներ &gt; Հատուկ գործառույթներ։"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Միացնե՞լ <xliff:g id="SERVICE">%1$s</xliff:g>-ի դյուրանցումը"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ձայնի կարգավորման երկու կոճակները մի քանի վայրկյան սեղմած պահելով կմիացնեք <xliff:g id="SERVICE">%1$s</xliff:g> ծառայությունը, որը հատուկ գործառույթ է։ Դրա արդյունքում սարքի աշխատաեղանակը կարող է փոխվել։\n\nԱյս դյուրանցումը մեկ այլ գործառույթով փոխելու համար անցեք Կարգավորումներ &gt; Հատուկ գործառույթներ։"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Միացնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index df61452..47dd2a2 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -58,8 +58,8 @@
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Nomor Penelepon Masuk"</string>
     <string name="ClirMmi" msgid="6752346475055446417">"Menyembunyikan ID Penelepon untuk Panggilan Keluar"</string>
-    <string name="ColpMmi" msgid="4736462893284419302">"ID Saluran yang Tersambung"</string>
-    <string name="ColrMmi" msgid="5889782479745764278">"Batasan ID Saluran yang Tersambung"</string>
+    <string name="ColpMmi" msgid="4736462893284419302">"ID Saluran yang Terhubung"</string>
+    <string name="ColrMmi" msgid="5889782479745764278">"Batasan ID Saluran yang Terhubung"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Penerusan panggilan"</string>
     <string name="CwMmi" msgid="3164609577675404761">"Nada tunggu"</string>
     <string name="BaMmi" msgid="7205614070543372167">"Pemblokiran panggilan"</string>
@@ -162,7 +162,7 @@
     <string name="httpErrorUnsupportedAuthScheme" msgid="3976195595501606787">"Skema autentikasi situs tidak didukung."</string>
     <string name="httpErrorAuth" msgid="469553140922938968">"Tidak dapat mengautentikasi."</string>
     <string name="httpErrorProxyAuth" msgid="7229662162030113406">"Autentikasi via proxy server gagal."</string>
-    <string name="httpErrorConnect" msgid="3295081579893205617">"Tidak dapat tersambung ke server."</string>
+    <string name="httpErrorConnect" msgid="3295081579893205617">"Tidak dapat terhubung ke server."</string>
     <string name="httpErrorIO" msgid="3860318696166314490">"Tidak dapat berkomunikasi dengan server. Coba lagi nanti."</string>
     <string name="httpErrorTimeout" msgid="7446272815190334204">"Koneksi ke server terputus."</string>
     <string name="httpErrorRedirectLoop" msgid="8455757777509512098">"Halaman ini berisi terlalu banyak pengalihan server."</string>
@@ -326,12 +326,12 @@
     <string name="permgroupdesc_phone" msgid="270048070781478204">"melakukan dan mengelola panggilan telepon"</string>
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensor tubuh"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"mengakses data sensor tentang tanda-tanda vital"</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Mengambil konten jendela"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Memeriksa konten jendela tempat Anda berinteraksi."</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Membaca konten di jendela"</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Memeriksa konten di jendela yang sedang Anda buka."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Mengaktifkan Jelajahi dengan Sentuhan"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Item yang diketuk akan diucapkan dengan jelas dan layar dapat dijelajahi menggunakan gestur."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Mengamati teks yang Anda ketik"</string>
-    <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Meliputi data pribadi seperti nomor kartu kredit dan sandi."</string>
+    <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Termasuk data pribadi, seperti nomor kartu kredit dan sandi."</string>
     <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Mengontrol perbesaran layar"</string>
     <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Mengontrol tingkat zoom dan pemosisian layar."</string>
     <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Melakukan isyarat"</string>
@@ -468,7 +468,7 @@
     <string name="permlab_accessImsCallService" msgid="442192920714863782">"akses layanan panggilan IMS"</string>
     <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Memungkinkan aplikasi menggunakan layanan IMS untuk melakukan panggilan tanpa campur tangan Anda."</string>
     <string name="permlab_readPhoneState" msgid="8138526903259297969">"baca identitas dan status ponsel"</string>
-    <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
+    <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang terhubung oleh sebuah panggilan."</string>
     <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"sambungkan panggilan telepon melalui sistem"</string>
     <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Mengizinkan aplikasi menyambungkan panggilan telepon melalui sistem untuk menyempurnakan pengalaman menelepon."</string>
     <string name="permlab_callCompanionApp" msgid="3654373653014126884">"melihat dan mengontrol panggilan melalui sistem."</string>
@@ -504,7 +504,7 @@
     <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Mengizinkan aplikasi mendapatkan daftar akun yang dikenal oleh perangkat Android TV. Ini mungkin mencakup akun yang dibuat oleh aplikasi yang telah Anda instal."</string>
     <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Memungkinkan aplikasi mendapatkan daftar akun yang dikenal oleh ponsel. Ini mungkin termasuk akun yang dibuat oleh aplikasi yang telah Anda instal."</string>
     <string name="permlab_accessNetworkState" msgid="2349126720783633918">"lihat koneksi jaringan"</string>
-    <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Memungkinkan aplikasi melihat informasi tentang koneksi jaringan, misalnya jaringan yang ada dan tersambung."</string>
+    <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Memungkinkan aplikasi melihat informasi tentang koneksi jaringan, misalnya jaringan yang ada dan terhubung."</string>
     <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"dapatkan akses jaringan penuh"</string>
     <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Memungkinkan aplikasi membuat soket jaringan dan menggunakan protokol jaringan khusus. Browser dan aplikasi lain menyediakan sarana untuk mengirim data ke internet sehingga izin ini tidak diperlukan untuk mengirim data ke internet."</string>
     <string name="permlab_changeNetworkState" msgid="8945711637530425586">"ubah konektivitas jaringan"</string>
@@ -512,7 +512,7 @@
     <string name="permlab_changeTetherState" msgid="9079611809931863861">"mengubah konektivitas yang tertambat"</string>
     <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Mengizinkan apl mengubah status konektivitas jaringan yang tertambat."</string>
     <string name="permlab_accessWifiState" msgid="5552488500317911052">"lihat sambungan Wi-Fi"</string>
-    <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Memungkinkan aplikasi melihat informasi tentang jaringan Wi-Fi, misalnya apakah Wi-Fi diaktifkan dan nama perangkat Wi-Fi yang tersambung."</string>
+    <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Memungkinkan aplikasi melihat informasi tentang jaringan Wi-Fi, misalnya apakah Wi-Fi diaktifkan dan nama perangkat Wi-Fi yang terhubung."</string>
     <string name="permlab_changeWifiState" msgid="7947824109713181554">"sambung dan putuskan Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Memungkinkan aplikasi menyambung ke dan memutus dari titik akses Wi-Fi, dan mengubah konfigurasi perangkat untuk jaringan Wi-Fi."</string>
     <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"Izinkan penerimaan Wi-Fi Multicast"</string>
@@ -524,14 +524,14 @@
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Mengizinkan aplikasi mengonfigurasi Bluetooth di perangkat Android TV, serta menemukan dan menyambungkan dengan perangkat jarak jauh."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Mengizinkan apl mengonfigurasi ponsel Bluetooth lokal, dan menemukan serta menyandingkan dengan perangkat jarak jauh."</string>
     <string name="permlab_accessWimaxState" msgid="7029563339012437434">"sambungkan dan putuskan dari WiMAX"</string>
-    <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Memungkinkan aplikasi menentukan apakah WiMAX diaktifkan dan informasi tentang jaringan WiMAX apa saja yang tersambung."</string>
+    <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Memungkinkan aplikasi menentukan apakah WiMAX diaktifkan dan informasi tentang jaringan WiMAX apa saja yang terhubung."</string>
     <string name="permlab_changeWimaxState" msgid="6223305780806267462">"Ganti status WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Memungkinkan aplikasi menyambungkan tablet ke dan memutus tablet dari jaringan WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Mengizinkan aplikasi menghubungkan perangkat Android TV ke, dan memutuskan hubungan perangkat Android TV dari, jaringan WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Memungkinkan aplikasi menyambungkan ponsel ke dan memutus ponsel dari jaringan WiMAX."</string>
     <string name="permlab_bluetooth" msgid="586333280736937209">"sambungkan dengan perangkat Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di tablet, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
-    <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Mengizinkan aplikasi melihat konfigurasi Bluetooth di perangkat Android TV, serta melakukan dan menerima sambungan dengan perangkat yang tersambung."</string>
+    <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Mengizinkan aplikasi melihat konfigurasi Bluetooth di perangkat Android TV, serta melakukan dan menerima sambungan dengan perangkat yang terhubung."</string>
     <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di ponsel, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
     <string name="permlab_bluetooth_scan" msgid="5402587142833124594">"temukan &amp; sambungkan perangkat Bluetooth di sekitar"</string>
     <string name="permdesc_bluetooth_scan" product="default" msgid="6540723536925289276">"Mengizinkan aplikasi menemukan dan menyambungkan perangkat Bluetooth di sekitar"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gunakan sidik jari atau kunci layar untuk melanjutkan"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon sidik jari"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Masalah pada Face Unlock"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan face lock atau kunci layar untuk melanjutkan"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"baca setelan sinkronisasi"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Memungkinkan aplikasi membaca setelan sinkronisasi untuk sebuah akun. Misalnya, izin ini dapat menentukan apakah aplikasi Orang disinkronkan dengan sebuah akun."</string>
@@ -1366,7 +1370,7 @@
     <string name="usb_ptp_notification_title" msgid="5043437571863443281">"PTP via USB diaktifkan"</string>
     <string name="usb_tether_notification_title" msgid="8828527870612663771">"Tethering USB diaktifkan"</string>
     <string name="usb_midi_notification_title" msgid="7404506788950595557">"MIDI via USB diaktifkan"</string>
-    <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Aksesori USB tersambung"</string>
+    <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Aksesori USB terhubung"</string>
     <string name="usb_notification_message" msgid="4715163067192110676">"Ketuk untuk opsi lainnya."</string>
     <string name="usb_power_notification_message" msgid="7284765627437897702">"Mengisi daya perangkat yang terhubung. Ketuk untuk opsi lainnya."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Aksesori audio analog terdeteksi"</string>
@@ -1498,9 +1502,9 @@
     <string name="vpn_title" msgid="5906991595291514182">"VPN diaktifkan"</string>
     <string name="vpn_title_long" msgid="6834144390504619998">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="2275388920267251078">"Ketuk untuk mengelola jaringan."</string>
-    <string name="vpn_text_long" msgid="278540576806169831">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
+    <string name="vpn_text_long" msgid="278540576806169831">"Terhubung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
     <string name="vpn_lockdown_connecting" msgid="6096725311950342607">"Menyambungkan VPN selalu aktif..."</string>
-    <string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN selalu aktif tersambung"</string>
+    <string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN selalu aktif terhubung"</string>
     <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"Terputus dari VPN yang selalu aktif"</string>
     <string name="vpn_lockdown_error" msgid="4453048646854247947">"Tidak dapat terhubung ke VPN yang selalu aktif"</string>
     <string name="vpn_lockdown_config" msgid="8331697329868252169">"Ubah setelan jaringan atau VPN"</string>
@@ -1635,7 +1639,7 @@
     <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Setelan"</string>
     <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Putuskan koneksi"</string>
     <string name="media_route_status_scanning" msgid="8045156315309594482">"Memindai..."</string>
-    <string name="media_route_status_connecting" msgid="5845597961412010540">"Menyambung..."</string>
+    <string name="media_route_status_connecting" msgid="5845597961412010540">"Menghubungkan..."</string>
     <string name="media_route_status_available" msgid="1477537663492007608">"Tersedia"</string>
     <string name="media_route_status_not_available" msgid="480912417977515261">"Tidak tersedia"</string>
     <string name="media_route_status_in_use" msgid="6684112905244944724">"Sedang digunakan"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Aktifkan pintasan untuk fitur aksesibilitas?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Menahan kedua tombol volume selama beberapa detik akan mengaktifkan fitur aksesibilitas. Tindakan ini dapat mengubah cara kerja perangkat Anda.\n\nFitur saat ini:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAnda dapat mengubah fitur yang dipilih di Setelan &gt; Aksesibilitas."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Aktifkan pintasan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Menahan kedua tombol volume selama beberapa detik akan mengaktifkan <xliff:g id="SERVICE">%1$s</xliff:g>, yang merupakan fitur aksesibilitas. Tindakan ini dapat mengubah cara kerja perangkat Anda.\n\nAnda dapat mengubah pintasan ini ke fitur lain di Setelan &gt; Aksesibilitas."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktifkan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index abd7735..59d0e4b 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Notaðu fingrafar eða skjálás til að halda áfram"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingrafaratákn"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Andlitskenni"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Vandamál varðandi andlitskenni"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Notaðu andlitið eða skjálás til að halda áfram"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Andlitstákn"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lesa samstillingar"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Leyfir forriti að lesa kosti samstillingar fyrir reikning. Þetta er til dæmis hægt að nota til að komast að því hvort forritið Fólk er samstillt við reikning."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Kveikja á flýtileið fyrir aðgangseiginleika?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Kveikt er á aðgengiseiginleikum þegar báðum hljóðstyrkstökkunum er haldið inni í nokkrar sekúndur. Þetta getur breytt því hvernig tækið virkar.\n\nNúverandi eiginleikar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÞú getur breytt völdum eiginleikum í Stillingar &gt; Aðgengi."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Kveikja á flýtileið <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ef báðum hljóðstyrkstökkunum er haldið inni í nokkrar sekúndur er kveikt á aðgengiseiginleikanum <xliff:g id="SERVICE">%1$s</xliff:g>. Þetta getur breytt því hvernig tækið virkar.\n\nÞú getur breytt þessari flýtileið í annan eiginleika í Stillingar &gt; Aðgengi."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Kveikja"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b35132e..62f87a9 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -327,13 +327,13 @@
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensori del corpo"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperare contenuti della finestra"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Esaminare i contenuti di una finestra con cui interagisci."</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Esamina i contenuti di una finestra con cui interagisci."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Attivare Esplora al tocco"</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Gli elementi toccati verranno pronunciati ad alta voce e sarà possibile esplorare lo schermo utilizzando i gesti."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Gli elementi toccati verranno pronunciati ad alta voce e sarà possibile esplorare lo schermo con i gesti."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Osservare il testo digitato"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Sono inclusi dati personali come numeri di carte di credito e password."</string>
     <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Controllare l\'ingrandimento del display"</string>
-    <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controlla il livello di zoom e la posizione del display."</string>
+    <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controlla la posizione e il livello di zoom del display."</string>
     <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Eseguire gesti"</string>
     <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
     <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesti con sensore di impronte"</string>
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Per continuare devi usare la tua impronta o il tuo blocco schermo"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Si è verificato un errore. Riprova."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona dell\'impronta"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Sblocco con il volto"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con Sblocco con il volto"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Per continuare devi usare il tuo volto o il tuo blocco schermo"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Si è verificato un errore. Riprova."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Icona volto"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lettura impostazioni di sincronizz."</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vuoi attivare la scorciatoia per le funzioni di accessibilità?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Se tieni premuti entrambi i tasti del volume per qualche secondo, vengono attivate le funzioni di accessibilità. Questa operazione potrebbe modificare il funzionamento del dispositivo.\n\nFunzioni correnti:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuoi modificare le funzioni selezionate in Impostazioni &gt; Accessibilità."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vuoi attivare la scorciatoia per <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Se tieni premuti entrambi i tasti del volume per qualche secondo verrà attivata la funzione di accessibilità <xliff:g id="SERVICE">%1$s</xliff:g>. Questa operazione potrebbe modificare il funzionamento del dispositivo.\n\nPuoi associare questa scorciatoia a un\'altra funzionalità in Impostazioni &gt; Accessibilità."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Attiva"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 2daf5b1..7ccec0f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"יש להשתמש בטביעת האצבע או בנעילת המסך כדי להמשיך"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"סמל טביעת אצבע"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"פתיחה ע\"י זיהוי הפנים"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"בעיה בפתיחה ע\"י זיהוי הפנים"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"יש להשתמש בזיהוי הפנים או בנעילת המסך כדי להמשיך"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"סמל הפנים"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"קריאת הגדרות הסנכרון"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"מאפשרת לאפליקציה לקרוא את הגדרות הסנכרון של חשבון. לדוגמה, כך אפשר לדעת אם האפליקציה \'אנשים\' מסונכרנת עם חשבון כלשהו."</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"האם להפעיל את מקש הקיצור לתכונות הנגישות?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"לחיצה ארוכה על שני לחצני עוצמת הקול למשך מספר שניות מפעילה את תכונות הנגישות. בעקבות זאת, ייתכן שאופן הפעולה של המכשיר ישתנה.\n\nהתכונות הנוכחיות:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nניתן לשנות את התכונות שנבחרו ב\'הגדרות\' &gt; \'נגישות\'."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"האם להפעיל את מקש הקיצור של <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"לחיצה על שני מקשי עוצמת הקול למשך מספר שניות מפעילה את תכונת הנגישות <xliff:g id="SERVICE">%1$s</xliff:g>. ייתכן שאופן הפעולה של המכשיר ישתנה בעקבות זאת.\n\nאפשר לשנות את מקשי הקיצור האלה לתכונה אחרת ב\'הגדרות\' &gt; \'נגישות\'."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"אני רוצה להפעיל"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 1f9f4ab..93fd395 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"続行するには、指紋認証または画面ロックを使用してください"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋アイコン"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"顔認証"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"顔認証に関する問題"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"続行するには、顔認証または画面ロックを使用してください"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"顔アイコン"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"同期設定の読み取り"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ショートカットが ON の場合、両方の音量ボタンを 3 秒ほど長押しするとユーザー補助機能が起動します。"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ユーザー補助機能のショートカットを ON にしますか?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\n現在の機能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n選択した機能は [設定] &gt; [ユーザー補助] で変更できます。"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> のショートカットを ON にしますか?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能の <xliff:g id="SERVICE">%1$s</xliff:g> が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\nこのショートカットは [設定] &gt; [ユーザー補助] で別の機能に変更できます。"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ON にする"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 09b3c2b..3648788 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -57,7 +57,7 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"შემომავალი ზარის აბონენტის ID"</string>
-    <string name="ClirMmi" msgid="6752346475055446417">"გამავალი აბონენტის ID-ის დამალვა"</string>
+    <string name="ClirMmi" msgid="6752346475055446417">"გამავალი აბონენტის ID-ს დამალვა"</string>
     <string name="ColpMmi" msgid="4736462893284419302">"დაუკავშირდა Line ID-ს"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"დაუკავშირდა Line ID Restriction-ს"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ზარის გადამისამართება"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი ან ეკრანის განბლოკვის ნიმუში"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"თითის ანაბეჭდის ხატულა"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"განბლოკვა სახით"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"პრობლემა სახით განბლოკვასთან დაკავშირებით"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"გასაგრძელებლად გამოიყენეთ თქვენი სახე ან ეკრანის განბლოკვის ნიმუში"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"სახის ხატულა"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"სინქრონიზაციის პარამეტრების წაკითხვა"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"აპს შეეძლება, წაიკითხოს ანგარიშის სინქრონიზაციის პარამეტრები. მაგალითად, მას შეეძლება განსაზღვროს, არის თუ არა People აპი სინქრონიზებული ანგარიშთან."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"თუ მალსახმობი ჩართულია, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ჩაირთოს მარტივი წვდომის ფუნქციების მალსახმობი?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ხმის ორივე ღილაკზე ხანგრძლივად დაჭერა რამდენიმე წამის განმავლობაში ჩართავს მარტივი წვდომის ფუნქციებს. ამ ქმედებამ შეიძლება შეცვალოს თქვენი მოწყობილობის მუშაობის პრინციპი.\n\nამჟამინდელი ფუნქციები:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nარჩეული ფუნქციების შეცვლა შესაძლებელია აქ: პარამეტრები &gt; მარტივი წვდომა."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ჩაირთოს <xliff:g id="SERVICE">%1$s</xliff:g>-ის მალსახმობი?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ხმის ორივე ღილაკზე რამდენიმე წამის განმავლობაში დაჭერით ჩაირთვება <xliff:g id="SERVICE">%1$s</xliff:g>, რომელიც მარტივი წვდომის ფუნქციაა. ამან შეიძლება შეცვალოს თქვენი მოწყობილობის მუშაობის პრინციპი.\n\nამ მალსახმობის შეცვლა სხვა ფუნქციით შეგიძლიათ აქ: პარამეტრები &gt; აპები."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ჩართვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d9fde8f..c42e849 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Жалғастыру үшін саусақ ізін немесе экран құлпын пайдаланыңыз."</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Саусақ ізі белгішесі"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Бет тану"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Бет тану функциясына қатысты мәселе шықты"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Жалғастыру үшін бетті анықтау функциясын немесе экран құлпын пайдаланыңыз."</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Бет белгішесі"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"синх параметрлерін оқу"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Қолданбаға есептік жазба синхрондау параметрлерін оқу мүмкіндігін береді. Мысалы, бұл арқылы People қолданбасының есептік жазбамен сихрондалғаны анықталуы мүмкін."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Түймелер тіркесімі қосулы кезде, екі дыбыс түймесін 3 секунд басып тұрсаңыз, \"Арнайы мүмкіндіктер\" функциясы іске қосылады."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Арнайы мүмкіндіктердің жылдам пәрмені іске қосылсын ба?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, арнайы мүмкіндіктер іске қосылады. Бұл – құрылғының жұмысына әсер етуі мүмкін.\n\nҚазіргі функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТаңдалған функцияларды \"Параметрлер &gt; Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> жылдам пәрмені іске қосылсын ба?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, <xliff:g id="SERVICE">%1$s</xliff:g> арнайы қызметі іске қосылады. Бұл – құрылғының жүмысына әсер етуі мүмкін.\n\nБұл таңбашаны басқа функцияға \"Параметрлер &gt; Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Қосылсын"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 716e810..6418a6e 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ប្រើការចាក់សោអេក្រង់ ឬស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"រូបស្នាមម្រាមដៃ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ដោះ​សោ​តាម​​ទម្រង់​មុខ"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"មានបញ្ហា​ពាក់ព័ន្ធនឹង​មុខងារ​ដោះសោ​តាមទម្រង់មុខ"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ប្រើការចាក់សោអេក្រង់ ឬមុខរបស់អ្នក ដើម្បីបន្ត"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"រូប​ផ្ទៃមុខ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"អាន​ការ​កំណត់​ធ្វើ​សម​កាល​កម្ម"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ឲ្យ​កម្មវិធី​អាន​ការ​កំណត់​ធ្វើ​សម​កាល​កម្ម​សម្រាប់​គណនី។ ឧទាហរណ៍ វា​អាច​កំណត់​ថា​តើ​​​កម្មវិធី​ត្រូវ​បាន​បើក​ជា​មួយ​គណនី​ដែរ​ឬទេ។"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"នៅពេលបើក​ផ្លូវកាត់ ការចុច​ប៊ូតុង​កម្រិតសំឡេង​ទាំងពីរ​រយៈពេល 3 វិនាទី​នឹង​ចាប់ផ្តើម​មុខងារ​ភាពងាយប្រើ។"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"បើក​ផ្លូវកាត់​សម្រាប់មុខងារ​ភាពងាយស្រួលឬ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ការសង្កត់​គ្រាប់ចុច​កម្រិតសំឡេង​ទាំងពីរ​ឱ្យជាប់​រយៈពេល​ពីរបីវិនាទី​នឹងបើក​មុខងារ​ភាពងាយប្រើ។ ការធ្វើ​បែបនេះ​អាចផ្លាស់ប្ដូរ​របៀបដែល​ឧបករណ៍​របស់អ្នក​ដំណើរការ។\n\nមុខងារ​បច្ចុប្បន្ន៖\n<xliff:g id="SERVICE">%1$s</xliff:g>\nអ្នកអាច​ប្ដូរ​មុខងារ​ដែលបាន​ជ្រើសរើស​នៅក្នុង​ការកំណត់ &gt; ភាពងាយស្រួល។"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"បើក​ផ្លូវកាត់ <xliff:g id="SERVICE">%1$s</xliff:g> ឬ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ការសង្កត់​គ្រាប់ចុច​កម្រិតសំឡេង​ទាំងពីរ​ឱ្យជាប់​រយៈពេល​ពីរបីវិនាទី​នឹងបើក <xliff:g id="SERVICE">%1$s</xliff:g> ដែលជា​មុខងារ​ភាពងាយប្រើ។ ការធ្វើ​បែបនេះ​អាចផ្លាស់ប្ដូរ​របៀបដែល​ឧបករណ៍​របស់អ្នក​ដំណើរការ។\n\nអ្នកអាច​ប្ដូរផ្លូវកាត់​នេះទៅ​មុខងារ​ផ្សេងទៀត​នៅក្នុង​ការកំណត់ &gt; ភាពងាយស្រួល។"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"បើក"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 4d328d3..6c21e3e 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -306,7 +306,7 @@
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"ಸ್ಥಳ"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"ಈ ಸಾಧನದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
-    <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+    <string name="permgrouplab_calendar" msgid="6426860926123033230">"ಕ್ಯಾಲೆಂಡರ್"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ನಿರ್ವಹಿಸಲು"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ಮುಂದುವರಿಸಲು ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ಫೇಸ್ ಅನ್‌ಲಾಕ್"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ಫೇಸ್ ಅನ್‌ಲಾಕ್ ಕುರಿತು ಸಮಸ್ಯೆ ಇದೆ"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಮುಖ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ಮುಖದ ಐಕಾನ್‌"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ರೀಡ್‌ ಮಾಡು"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ಒಂದು ಖಾತೆಯ ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್‍‍ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಖಾತೆಯೊಂದಿಗೆ ಜನರ ಅಪ್ಲಿಕೇಶನ್ ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಇದು ನಿರ್ಧರಿಸಬಹುದು."</string>
@@ -815,7 +819,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ಕಚೇರಿ ಮೊಬೈಲ್"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"ಕಚೇರಿ ಪೇಜರ್"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"ಅಸಿಸ್ಟೆಂಟ್"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"ಕಸ್ಟಮ್"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"ಜನ್ಮದಿನ"</string>
@@ -848,7 +852,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"ಇತರೆ"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"ಕಸ್ಟಮ್"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"ಕಸ್ಟಮ್"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"ಅಸಿಸ್ಟೆಂಟ್"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"ಸಹೋದರ"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"ಮಗು"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"ಸ್ಥಳೀಯ ಪಾಲುದಾರ"</string>
@@ -1038,9 +1042,9 @@
     <string name="menu_space_shortcut_label" msgid="5949311515646872071">"space"</string>
     <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>
     <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"ಅಳಿಸಿ"</string>
-    <string name="search_go" msgid="2141477624421347086">"Search"</string>
+    <string name="search_go" msgid="2141477624421347086">"ಹುಡುಕಿ"</string>
     <string name="search_hint" msgid="455364685740251925">"ಹುಡುಕಿ…"</string>
-    <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+    <string name="searchview_description_search" msgid="1045552007537359343">"ಹುಡುಕಿ"</string>
     <string name="searchview_description_query" msgid="7430242366971716338">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸು"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"ಪ್ರಶ್ನೆಯನ್ನು ಸಲ್ಲಿಸು"</string>
@@ -1468,7 +1472,7 @@
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ಝೂಮ್‌ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="gadget_host_error_inflating" msgid="2449961590495198720">"ವಿಜೆಟ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
     <string name="ime_action_go" msgid="5536744546326495436">"ಹೋಗು"</string>
-    <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+    <string name="ime_action_search" msgid="4501435960587287668">"ಹುಡುಕಿ"</string>
     <string name="ime_action_send" msgid="8456843745664334138">"ಕಳುಹಿಸು"</string>
     <string name="ime_action_next" msgid="4169702997635728543">"ಮುಂದೆ"</string>
     <string name="ime_action_done" msgid="6299921014822891569">"ಮುಗಿದಿದೆ"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ಶಾರ್ಟ್‌ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್‌ಗಳನ್ನು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಿದರೆ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವೊಂದು ಪ್ರಾರಂಭವಾಗುತ್ತದೆ."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳಿಗಾಗಿ ಶಾರ್ಟ್‌ಕಟ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಕೆಲವು ಸೆಕೆಂಡುಗಳ ಕಾಲ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳು ಆನ್ ಆಗುತ್ತವೆ. ಇದು ನಿಮ್ಮ ಸಾಧನವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಬಹುದು.\n\n ಪ್ರಸ್ತುತ ವೈಶಿಷ್ಟ್ಯಗಳು:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿಯಲ್ಲಿ ಆಯ್ದ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನೀವು ಬದಲಾಯಿಸಬಹುದು."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ಶಾರ್ಟ್‌ಕಟ್ <xliff:g id="SERVICE">%1$s</xliff:g>ಆನ್‌ ಮಾಡಬೇಕೇ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಕೆಲವು ಸೆಕೆಂಡುಗಳ ಕಾಲ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವಾದ <xliff:g id="SERVICE">%1$s</xliff:g> ಆನ್ ಆಗುತ್ತದೆ. ಇದು ನಿಮ್ಮ ಸಾಧನವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಬಹುದು.\n\nನೀವು ಈ ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಅಕ್ಸೆಸಿಬಿಲಿಟಿಯಲ್ಲಿನ ಮತ್ತೊಂದು ವೈಶಿಷ್ಟ್ಯಕ್ಕೆ ಬದಲಾಯಿಸಬಹುದು."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ಆನ್ ಮಾಡಿ"</string>
@@ -1973,7 +1978,7 @@
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"ಸೂಚಿತ ಭಾಷೆ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
     <string name="region_picker_section_all" msgid="756441309928774155">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
-    <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+    <string name="locale_search_menu" msgid="6258090710176422934">"ಹುಡುಕಿ"</string>
     <string name="app_suspended_title" msgid="888873445010322650">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ. ಇದನ್ನು <xliff:g id="APP_NAME_1">%2$s</xliff:g> ನಲ್ಲಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a0054c0..4657d52 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"계속하려면 지문이나 화면 잠금을 사용하세요"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"지문 아이콘"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"얼굴 인식 잠금 해제"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"얼굴 인식 잠금 해제 문제"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"계속하려면 얼굴 또는 화면 잠금을 사용하세요"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"얼굴 아이콘"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"동기화 설정 읽기"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"접근성 기능 바로가기를 사용 설정하시겠습니까?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"볼륨 키 2개를 몇 초 동안 길게 누르면 접근성 기능이 사용 설정됩니다. 이때 기기 작동 방식이 달라질 수 있습니다.\n\n현재 기능:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n설정 &gt; 접근성에서 선택한 기능을 변경할 수 있습니다."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> 바로가기를 사용 설정하시겠습니까?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"볼륨 키 2개를 몇 초 동안 길게 누르면 <xliff:g id="SERVICE">%1$s</xliff:g> 접근성 기능이 사용 설정됩니다. 이렇게 되면 기기 작동 방식이 달라질 수 있습니다.\n\n설정 &gt; 접근성에서 이 단축키를 다른 기능으로 변경할 수 있습니다."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"사용"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 45624a4..2458e11 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Улантуу үчүн манжа изин же экрандын кулпусун колдонуңуз"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Манжа изинин сүрөтчөсү"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Жүзүнөн таанып ачуу"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Жүзүнөн таанып ачуу функциясында маселе келип чыкты"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Улантуу үчүн жүзүңүздү же экрандын кулпусун колдонуңуз"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Жүздүн сүрөтчөсү"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"шайкештирүү жөндөөлөрүн окуу"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Колдонмого эсеп менен синхрондошуу тууралоолорун окуганга уруксат берет. Мисалы, Кишилер колдонмосу эсеп менен синхрондошкондугун аныктай алат."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 7544c39..935df5a 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ໃຊ້ລາຍນິ້ວມື ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ໄອຄອນລາຍນິ້ວມື"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ປົດລັອກດ້ວຍໜ້າ"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ເກີດບັນຫາກັບການປົດລັອກດ້ວຍໜ້າ"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ໃຊ້ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ໄອຄອນໃບໜ້າ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ອ່ານການຕັ້ງຄ່າຊິ້ງຂໍ້ມູນ"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການຕັ້ງຄ່າການຊິ້ງຂໍ້ມູນຂອງບັນຊີໄດ້. ຕົວຢ່າງເຊັ່ນ: ມັນຈະສາມາດກວດສອບໄດ້ແອັບຯ People ຖືກຊິ້ງຂໍ້ມູນກັບບັນຊີໃດນຶ່ງແລ້ວຫຼືຍັງ."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ເມື່ອເປີດໃຊ້ທາງລັດແລ້ວ, ການກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີຈະເປັນການເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ເປີດໃຊ້ທາງລັດສຳລັບຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ສອງສາມວິນາທີເພື່ອເປີດໃຊ້ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ນີ້ອາດປ່ຽນວິທີການເຮັດວຽກຂອງອຸປະກອນທ່ານ.\n\nຄຸນສົມບັດປັດຈຸບັນ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nທ່ານສາມາດປ່ຽນຄຸນສົມບັດທີ່ເລືອກໄດ້ໃນການຕັ້ງຄ່າ &gt; ການຊ່ວຍເຂົ້າເຖິງ."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ເປີດໃຊ້ທາງລັດ <xliff:g id="SERVICE">%1$s</xliff:g> ບໍ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ສອງສາມວິນາທີເພື່ອເປີດໃຊ້ <xliff:g id="SERVICE">%1$s</xliff:g>, ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ນີ້ອາດປ່ຽນວິທີການເຮັດວຽກຂອງອຸປະກອນທ່ານ.\n\nທ່ານສາມາດປ່ຽນທາງລັດນີ້ເປັນຄຸນສົມບັດອື່ນໄດ້ໃນການຕັ້ງຄ່າ &gt; ການຊ່ວຍເຂົ້າເຖິງ."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ເປີດໃຊ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 18ac1b1..7317f5f 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jei norite tęsti, naudokite kontrolinį kodą arba ekrano užraktą"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Piršto antspaudo piktograma"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Atrakinimas pagal veidą"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Su atrakinimu pagal veidą susijusi problema"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jei norite tęsti, naudokite veido atpažinimo funkciją arba ekrano užraktą"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Veido pkt."</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"skaityti sinchronizavimo nustatymus"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Leidžiama programai skaityti ir sinchronizuoti paskyros nustatymus. Pvz., taip gali būti nustatoma, ar su paskyra sinchronizuota Žmonių programa."</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kai spartusis klavišas įjungtas, paspaudus abu garsumo mygtukus ir palaikius 3 sekundes bus įjungta pritaikymo neįgaliesiems funkcija."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Įjungti pritaikymo neįgaliesiems funkcijų spartųjį klavišą?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Paspaudus abu garsumo klavišus ir palaikius kelias sekundes įjungiamos pritaikymo neįgaliesiems funkcijos. Tai gali pakeisti įrenginio veikimą.\n\nDabartinės funkcijos:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPasirinktas funkcijas galite pakeisti skiltyje „Nustatymai“ &gt; „Pritaikomumas“."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Įjungti „<xliff:g id="SERVICE">%1$s</xliff:g>“ spartųjį klavišą?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Paspaudus abu garsumo klavišus ir palaikius kelias sekundes įjungiama pritaikymo neįgaliesiems funkcija „<xliff:g id="SERVICE">%1$s</xliff:g>“. Tai gali pakeisti įrenginio veikimą.\n\nGalite pakeisti šį spartųjį klavišą į kitą funkciją skiltyje „Nustatymai“ &gt; „Pritaikomumas“."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Įjungti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1799e38..db4587e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -612,6 +612,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Izmantojiet pirksta nospiedumu vai ekrāna bloķēšanas opciju, lai turpinātu"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pirksta nospieduma ikona"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Autorizācija pēc sejas"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problēma ar autorizāciju pēc sejas"</string>
@@ -664,6 +666,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Izmantojiet autorizāciju pēc sejas vai ekrāna bloķēšanas opciju, lai turpinātu"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Sejas ikona"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lasīt sinhronizācijas iestatījumus"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ļauj lietotnei lasīt konta sinhronizācijas iestatījumus. Piemēram, šādi var noteikt, vai lietotne Personas ir sinhronizēta ar kontu."</string>
@@ -1714,7 +1718,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad īsinājumtaustiņš ir ieslēgts, nospiežot abas skaļuma pogas un 3 sekundes turot tās, tiks aktivizēta pieejamības funkcija."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vai ieslēgt pieejamības funkciju saīsni?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Turot nospiestus abus skaļuma taustiņus dažas sekundes, tiek ieslēgtas pieejamības funkcijas. Tas var mainīt ierīces darbību.\n\nPašreizējās funkcijas:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAtlasītās funkcijas varat mainīt šeit: Iestatījumi &gt; Pieejamība."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vai ieslēgt <xliff:g id="SERVICE">%1$s</xliff:g> saīsni?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Turot nospiestus abus skaļuma taustiņus dažas sekundes, tiek ieslēgta pieejamības funkcija <xliff:g id="SERVICE">%1$s</xliff:g>. Tas var mainīt ierīces darbību.\n\nŠo saīsni uz citu funkciju varat mainīt šeit: Iestatījumi &gt; Pieejamība."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ieslēgt"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 39c3b8a..09f6230 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Користете го вашиот отпечаток или заклучување екран за да продолжите"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатоци"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Отклучување со лик"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем со „Отклучување со лик“"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користете отклучување со лик или заклучување екран за да продолжите"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Икона"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"чита поставки за синхронизација"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Овозможува апликацијата да ги чита поставките за синхронизирање на сметка. На пример, така може да се утврди дали апликацијата „Луѓе“ е синхронизирана со сметка."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција за пристапност."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Да се вклучи кратенка за функциите за пристапност?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ако ги задржите притиснати двете копчиња за јачина на звук неколку секунди, ќе се вклучат функциите за пристапност. Ова може да го промени начинот на функционирање на уредот.\n\nТековни функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМоже да ги промените избраните функции во „Поставки &gt; Пристапност“."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Да се вклучи кратенка за <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ако ги задржите притиснати двете копчиња за јачина на звук неколку секунди, ќе се вклучи функцијата за пристапност <xliff:g id="SERVICE">%1$s</xliff:g>. Ова може да го промени начинот на функционирање на уредот.\n\nМоже да ја измените кратенкава да биде за друга функција во „Поставки &gt; Пристапност“."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Вклучи"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d6491b7..f36e02f 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഓഫ്\'"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"ശബ്‌ദം"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ഡാറ്റ"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ഫാക്സ്"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"തുടരാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റ്‌ അല്ലെങ്കിൽ സ്‌ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ഫെയ്‌സ് അൺലോക്ക്"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ഫെയ്‌സ് അൺലോക്കുമായി ബന്ധപ്പെട്ട പ്രശ്നം"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"തുടരാൻ നിങ്ങളുടെ മുഖം‌ അല്ലെങ്കിൽ സ്‌ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"മുഖത്തിന്റെ ഐക്കൺ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string>
@@ -815,7 +819,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ഓഫീസ് മൊബൈല്‍"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"ഔദ്യോഗിക പേജര്‍‌"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"അസിസ്റ്റന്‍റ്"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"അസിസ്റ്റന്റ്"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"ഇഷ്‌ടാനുസൃതം"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"ജന്മദിനം"</string>
@@ -1038,9 +1042,9 @@
     <string name="menu_space_shortcut_label" msgid="5949311515646872071">"space"</string>
     <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>
     <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"delete"</string>
-    <string name="search_go" msgid="2141477624421347086">"Search"</string>
+    <string name="search_go" msgid="2141477624421347086">"തിരയുക"</string>
     <string name="search_hint" msgid="455364685740251925">"തിരയുക…"</string>
-    <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+    <string name="searchview_description_search" msgid="1045552007537359343">"തിരയുക"</string>
     <string name="searchview_description_query" msgid="7430242366971716338">"തിരയൽ അന്വേഷണം"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"അന്വേഷണം മായ്‌ക്കുക"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"ചോദ്യം സമർപ്പിക്കുക"</string>
@@ -1468,7 +1472,7 @@
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"സൂം നിയന്ത്രണം ലഭിക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
     <string name="gadget_host_error_inflating" msgid="2449961590495198720">"വിജറ്റ് ചേർക്കാനായില്ല."</string>
     <string name="ime_action_go" msgid="5536744546326495436">"പോവുക"</string>
-    <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+    <string name="ime_action_search" msgid="4501435960587287668">"തിരയുക"</string>
     <string name="ime_action_send" msgid="8456843745664334138">"അയയ്‌ക്കുക"</string>
     <string name="ime_action_next" msgid="4169702997635728543">"അടുത്തത്"</string>
     <string name="ime_action_done" msgid="6299921014822891569">"പൂർത്തിയായി"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"കുറുക്കുവഴി ഓണായിരിക്കുമ്പോൾ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ഉപയോഗസഹായി ഫീച്ചറുകൾക്കുള്ള കുറുക്കുവഴി ഓണാക്കണോ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപ്പിടിക്കുന്നത്, ഉപയോഗസഹായി ഫീച്ചറുകൾ ഓണാക്കുന്നു. നിങ്ങളുടെ ഉപകരണം പ്രവർത്തിക്കുന്ന രീതിയെ ഇത് മാറ്റിയേക്കാം.\n\nനിലവിലുള്ള ഫീച്ചറുകൾ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nതിരഞ്ഞെടുത്ത ഫീച്ചറുകൾ ക്രമീകരണം &gt; ഉപയോഗസഹായി എന്നതിൽ മാറ്റാനാവും."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> കുറുക്കുവഴി ഓണാക്കണോ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപ്പിടിക്കുന്നത് ഉപയോഗസഹായി ഫീച്ചറായ <xliff:g id="SERVICE">%1$s</xliff:g> എന്നതിനെ ഓണാക്കുന്നു. നിങ്ങളുടെ ഉപകരണം പ്രവർത്തിക്കുന്ന വിധം ഇത് മാറ്റിയേക്കാം.\n\nക്രമീകരണം &gt; ഉപയോഗസഹായി എന്നതിലെ മറ്റൊരു ഫീച്ചറിലേക്ക് നിങ്ങൾക്ക് ഈ കുറുക്കുവഴി മാറ്റാനാവും."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ഓണാക്കുക"</string>
@@ -1973,7 +1978,7 @@
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"എല്ലാ ഭാഷകളും"</string>
     <string name="region_picker_section_all" msgid="756441309928774155">"എല്ലാ പ്രദേശങ്ങളും"</string>
-    <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+    <string name="locale_search_menu" msgid="6258090710176422934">"തിരയുക"</string>
     <string name="app_suspended_title" msgid="888873445010322650">"ആപ്പ് ലഭ്യമല്ല"</string>
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല. <xliff:g id="APP_NAME_1">%2$s</xliff:g> ആണ് ഇത് മാനേജ് ചെയ്യുന്നത്."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"കൂടുതലറിയുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index e17b884..e35571f 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Үргэлжлүүлэхийн тулд хурууны хээ эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Хурууны хээний дүрс"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Царайгаар түгжээ тайлах"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Царайгаар түгжээ тайлахтай холбоотой асуудал"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Үргэлжлүүлэхийн тулд царай эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Царайны дүрс тэмдэг"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"синк тохиргоог унших"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Апп нь бүртгэлийн синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Товчлол асаалттай үед дууны түвшний хоёр товчлуурыг хамтад нь 3 секунд дарснаар хандалтын онцлогийг эхлүүлнэ."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Хандалтын онцлогуудын товчлолыг асаах уу?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дууны түвшний түлхүүрийг хэдэн секундийн турш зэрэг дарснаар хандалтын онцлогууд асна. Энэ нь таны төхөөрөмжийн ажиллах зарчмыг өөрчилж болзошгүй.\n\nОдоогийн онцлогууд:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТа сонгосон онцлогуудыг Тохиргоо &gt; Хандалт хэсэгт өөрчлөх боломжтой."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>-н товчлолыг асаах уу?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дууны түвшний түлхүүрийг хэдэн секундийн турш зэрэг дарах нь хандалтын онцлог болох <xliff:g id="SERVICE">%1$s</xliff:g>-г асаадаг. Энэ нь таны төхөөрөмжийн ажиллах зарчмыг өөрчилж болзошгүй.\n\nТа Тохиргоо &gt; Хандалт хэсэгт энэ товчлолыг өөр онцлогт оноож өөрчлөх боломжтой."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Асаах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5195055..45762cd 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -471,7 +471,7 @@
     <string name="permdesc_readPhoneState" msgid="7229063553502788058">"डिव्हाइस च्या फोन वैशिष्ट्यांवर अ‍ॅक्सेस करण्यास ॲपला अनुमती देते. ही परवानगी कॉल ॲक्टिव्हेट असला किंवा नसला तरीही, फोन नंबर आणि डिव्हाइस आयडी आणि कॉलद्वारे कनेक्ट केलेला रिमोट नंबर निर्धारित करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"प्रणालीच्या माध्यमातून कॉल रूट करा"</string>
     <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"कॉल करण्याचा अनुभव सुधारण्यासाठी ॲपला त्याचे कॉल प्रणालीच्या माध्यमातून रूट करू देते."</string>
-    <string name="permlab_callCompanionApp" msgid="3654373653014126884">"सिस्टम वापरून कॉल पाहा आणि नियंत्रण ठेवा."</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>
@@ -581,7 +581,7 @@
     <string name="fingerprint_acquired_imager_dirty" msgid="5236744087471419479">"सेन्सर साफ करा"</string>
     <string name="fingerprint_acquired_too_fast" msgid="6038375140739678098">"जरा जास्त वेळ धरून ठेवा"</string>
     <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"बोट खूप सावकाश हलविले. कृपया पुन्हा प्रयत्न करा."</string>
-    <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पाहा"</string>
+    <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पहा"</string>
     <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string>
     <string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"अ‍ॅडजस्ट करण्याचा प्रयत्न करा"</string>
     <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"तुमच्या बोटाची स्थिती प्रत्येक वेळी थोडीशी बदला"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"पुढे सुरू ठेवण्यासाठी तुमचे फिंगरप्रिंट किंवा स्क्रीन लॉक वापरा"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिंट आयकन"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलॉक"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलॉकसंबंधित समस्या"</string>
@@ -629,7 +631,7 @@
     <string name="face_acquired_too_low" msgid="1512237819632165945">"फोन आणखी खाली हलवा."</string>
     <string name="face_acquired_too_right" msgid="2513391513020932655">"फोन डावीकडे हलवा."</string>
     <string name="face_acquired_too_left" msgid="8882499346502714350">"फोन उजवीकडे हलवा."</string>
-    <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"कृपया तुमच्या डिव्हाइसकडे थेट पाहा"</string>
+    <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"कृपया तुमच्या डिव्हाइसकडे थेट पहा"</string>
     <string name="face_acquired_not_detected" msgid="2945945257956443257">"तुमचा चेहरा थेट फोन समोर आणा."</string>
     <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"खूप हलत आहे. फोन स्थिर धरून ठेवा."</string>
     <string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया तुमच्या चेहऱ्याची पुन्हा नोंदणी करा."</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"पुढे सुरू ठेवण्यासाठी तुमचा चेहरा किंवा स्क्रीन लॉक वापरा"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"चेहरा आयकन"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"सिंक सेटिंग्‍ज वाचा"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"खात्याच्या सिंक सेटिंग्ज वाचण्यासाठी अ‍ॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांचा अ‍ॅप संकालित केला आहे किंवा नाही हे निर्धारित करू शकते."</string>
@@ -815,7 +819,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"कार्य मोबाइल"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"कार्य पेजर"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"असिस्टंट"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"कस्टम"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"वाढदिवस"</string>
@@ -1040,7 +1044,7 @@
     <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"हटवा"</string>
     <string name="search_go" msgid="2141477624421347086">"Search"</string>
     <string name="search_hint" msgid="455364685740251925">"शोधा…"</string>
-    <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+    <string name="searchview_description_search" msgid="1045552007537359343">"शोधा"</string>
     <string name="searchview_description_query" msgid="7430242366971716338">"शोध क्वेरी"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"क्‍वेरी साफ करा"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"क्वेरी सबमिट करा"</string>
@@ -1468,7 +1472,7 @@
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"झूम नियंत्रणासाठी दोनदा टॅप करा"</string>
     <string name="gadget_host_error_inflating" msgid="2449961590495198720">"विजेट जोडू शकलो नाही."</string>
     <string name="ime_action_go" msgid="5536744546326495436">"जा"</string>
-    <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+    <string name="ime_action_search" msgid="4501435960587287668">"शोधा"</string>
     <string name="ime_action_send" msgid="8456843745664334138">"पाठवा"</string>
     <string name="ime_action_next" msgid="4169702997635728543">"पुढे"</string>
     <string name="ime_action_done" msgid="6299921014822891569">"पूर्ण झाले"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्‍हॉल्‍यूम बटणे तीन सेकंदांसाठी दाबून ठेवल्याने अ‍ॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"अ‍ॅक्सेसिबिलिटी वैशिष्ट्यांसाठी शॉर्टकट सुरू करायचा आहे का?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने अ‍ॅक्सेसिबिलिटी वैशिष्ट्ये सुरू होतात. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nसध्याची वैशिष्ट्ये:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतुम्ही हा शॉर्टकट सेटिंग्ज &gt; अ‍ॅक्सेसिबिलिटी मध्ये बदलू शकता."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> शॉर्टकट सुरू करायचा आहे का?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने <xliff:g id="SERVICE">%1$s</xliff:g>, एक अ‍ॅक्सेसिबिलिटी वैशिष्ट्य सुरू होते. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nतुम्ही हा शॉर्टकट सेटिंग्ज &gt; अ‍ॅक्सेसिबिलिटी मध्ये बदलू शकता."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"सुरू करा"</string>
@@ -1702,9 +1707,9 @@
     <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> ला तुमचे डिव्हाइसच संपूर्णपणे नियंत्रित करायची अनुमती द्यायची का?"</string>
     <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"तुम्ही <xliff:g id="SERVICE">%1$s</xliff:g> सुरू केल्‍यास, तुमचे डिव्हाइस डेटा एंक्रिप्शनमध्ये सुधारणा करण्‍यासाठी स्क्रीन लॉक वापरणार नाही."</string>
     <string name="accessibility_service_warning_description" msgid="291674995220940133">"जी ॲप्स तुमच्या ॲक्सेसिबिलिटी गरजा पूर्ण करतात अशा ॲप्ससाठी संपूर्ण नियंत्रण योग्य आहे. पण ते सर्व ॲप्सना लागू होईल असे नाही."</string>
-    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन पाहा आणि नियंत्रित करा"</string>
+    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन पहा आणि नियंत्रित करा"</string>
     <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ते स्क्रीनवरील सर्व आशय वाचू शकते आणि इतर ॲप्सवर आशय प्रदर्शित करू शकते."</string>
-    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"पाहा आणि क्रिया करा"</string>
+    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"पहा आणि क्रिया करा"</string>
     <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"तुम्ही ॲप किंवा हार्डवेअर सेन्सर कसे वापरता याचा हे मागोवा घेऊ शकते आणि इतर ॲप्ससोबत तुमच्या वतीने काम करू शकते."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमती द्या"</string>
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"नकार द्या"</string>
@@ -1973,7 +1978,7 @@
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"सुचवलेल्या भाषा"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"सर्व भाषा"</string>
     <string name="region_picker_section_all" msgid="756441309928774155">"सर्व प्रदेश"</string>
-    <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+    <string name="locale_search_menu" msgid="6258090710176422934">"शोध"</string>
     <string name="app_suspended_title" msgid="888873445010322650">"अ‍ॅप उपलब्ध नाही"</string>
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> आत्ता उपलब्ध नाही. हे <xliff:g id="APP_NAME_1">%2$s</xliff:g> कडून व्यवस्थापित केले जाते."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"अधिक जाणून घ्या"</string>
@@ -1983,7 +1988,7 @@
     <string name="work_mode_turn_on" msgid="3662561662475962285">"सुरू करा"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
-    <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अ‍ॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पाहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string>
+    <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अ‍ॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेटसाठी तपासा"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"आपल्याकडे नवीन मेसेज आहेत"</string>
     <string name="new_sms_notification_content" msgid="3197949934153460639">"पाहण्‍यासाठी SMS अ‍ॅप उघडा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 76d52a9..f6cf330 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gunakan cap jari atau kunci skrin anda untuk meneruskan"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon cap jari"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Buka Kunci Wajah"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Isu dengan Buka Kunci Wajah"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan wajah atau kunci skrin anda untuk meneruskan"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"membaca tetapan penyegerakan"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Membenarkan apl membaca tetapan segerak untuk akaun. Sebagai contoh, ini boleh menentukan sama ada apl Orang disegerakkan dengan akaun."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Hidupkan pintasan untuk ciri kebolehaksesan?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Tindakan menahan kedua-dua kekunci kelantangan selama beberapa saat akan menghidupkan ciri kebolehaksesan. Hal ini mungkin mengubah cara peranti anda berfungsi.\n\nCiri semasa:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAnda boleh menukar ciri yang dipilih dalam Tetapan &gt; Kebolehaksesan."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Hidupkan pintasan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Tindakan menahan kedua-dua kekunci kelantangan selama beberapa saat akan menghidupkan <xliff:g id="SERVICE">%1$s</xliff:g>, iaitu satu ciri kebolehaksesan. Ini mungkin mengubah cara peranti anda berfungsi.\n\nAnda boleh menukar pintasan ini kepada ciri lain dalam Tetapan &gt; Kebolehaksesan."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Hidupkan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 74ecc1d..f0216d6 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ရှေ့ဆက်ရန် သင်၏ လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"လက်ဗွေ သင်္ကေတ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ ဆိုင်ရာ ပြဿနာ"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ရှေ့ဆက်ရန် သင်၏ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"မျက်နှာသင်္ကေတ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ထပ်တူပြုအဆင်အပြင်အားဖတ်ခြင်း"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"အပလီကေးရှင်းအား အကောင့်တစ်ခုအတွက် ထပ်တူညီအောင် လုပ်ဆောင်မှု ဆက်တင်အား ကြည့်ခွင့် ပြုပါ။ ဥပမာ People အက်ပ်က အကောင့်တစ်ခုနဲ့ ထပ်တူညီအောင် လုပ်ရန် ဆက်သွယ်ထားမှု ရှိမရှိ သိရှိနိုင်ခြင်း"</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံထိန်းခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများအတွက် ဖြတ်လမ်းကို ဖွင့်မလား။"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nလက်ရှိ ဝန်ဆောင်မှုများ-\n<xliff:g id="SERVICE">%1$s</xliff:g>\n\'ဆက်တင်များ &gt; အများသုံးစွဲနိုင်မှု\' တွင် ရွေးထားသည့် ဝန်ဆောင်မှုများကို ပြောင်းနိုင်သည်။"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ဖြတ်လမ်းကို ဖွင့်မလား။"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုဖြစ်သော <xliff:g id="SERVICE">%1$s</xliff:g> ကို ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nဤဖြတ်လမ်းလင့်ခ်ကို \'ဆက်တင်များ &gt; အများသုံးစွဲနိုင်မှု\' တွင် နောက်ဝန်ဆောင်မှုတစ်ခုသို့ ပြောင်းနိုင်သည်။"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ဖွင့်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4394e49..ac523f9 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Bruk fingeravtrykket eller skjermlåsen for å fortsette"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeravtrykk"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansiktslås"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem med ansiktslås"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Bruk ansikts- eller skjermlåsen for å fortsette"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ansiktikon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lese synkroniseringsinnstillinger"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lar appen lese synkroniseringsinnstillingene for en konto. For eksempel kan den finne ut om Personer-appen er synkronisert med en konto."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vil du slå på snarveien for tilgjengelighetsfunksjoner?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hvis du holder inne volumtastene i noen sekunder, slås tilgjengelighetsfunksjoner på. Dette kan endre hvordan enheten din fungerer.\n\nNåværende funksjoner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan endre valgte funksjoner i Innstillinger &gt; Tilgjengelighet."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vil du slå på <xliff:g id="SERVICE">%1$s</xliff:g>-snarveien?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hvis du holder inne begge volumtastene i noen sekunder, slår du på <xliff:g id="SERVICE">%1$s</xliff:g>, en tilgjengelighetsfunksjon. Dette kan endre hvordan enheten din fungerer.\n\nDu kan endre denne snarveien til en annen funksjon i Innstillinger &gt; Tilgjengelighet."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Slå på"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2d8b565..0751379 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"जारी राख्न आफ्नो फिंगरप्रिन्ट वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिन्ट आइकन"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलक"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलक सुविधामा अनुहार दर्ता गर्ने क्रममा त्रुटि भयो"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी राख्न आफ्नो फेस वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"अनुहारको आइकन"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"एपलाई खाताको लागि सिंक सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको एप खातासँग सिंक भएको नभएको निर्धारण गर्न सक्दछ।"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"यो सर्टकट सक्रिय हुँदा, ३ सेकेन्डसम्म दुवै भोल्युम बटन थिच्नुले पहुँचसम्बन्धी कुनै सुविधा सुरु गर्ने छ।"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"एक्सेसिबिलिटीसम्बन्धी सुविधा  प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"केही सेकेन्डसम्म दुवै भोल्युम की थिचिराख्नुभयो भने पहुँचसम्बन्धी सुविधाहरू सक्रिय हुन्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nहालका सुविधाहरू:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतपाईं सेटिङ &gt; पहुँचमा गएर चयन गरिएका सुविधाहरू परिवर्तन गर्न सक्नुहुन्छ।"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"केही सेकेन्डसम्म दुवै भोल्युम की थिचिराख्नुले <xliff:g id="SERVICE">%1$s</xliff:g> नामक पहुँचसम्बन्धी सुविधा  सक्रिय गर्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nतपाईं सेटिङ &gt; पहुँचमा गई यो सर्टकटमार्फत अर्को सुविधा खुल्ने बनाउन सक्नुहुन्छ।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"सक्रिय गरियोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0c61054..8c4021d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gebruik je vingerafdruk of schermvergrendeling om door te gaan"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ontgrendelen via gezichtsherkenning"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem met Ontgrendelen via gezichtsherkenning"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik je gezicht of schermvergrendeling om door te gaan"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Gezichtspictogram"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"synchronisatie-instellingen lezen"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Hiermee kan de app de synchronisatie-instellingen voor een account lezen. Dit kan bijvoorbeeld bepalen of de app Personen wordt gesynchroniseerd met een account."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Als de snelkoppeling aanstaat, houd je beide volumeknoppen 3 seconden ingedrukt om een toegankelijkheidsfunctie te starten."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Snelkoppeling voor toegankelijkheidsfuncties aanzetten?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Als je beide volumetoetsen een paar seconden ingedrukt houdt, zet je de toegankelijkheidsfuncties aan. Hierdoor kan de manier veranderen waarop je apparaat werkt.\n\nHuidige functies:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nJe kunt de geselecteerde functies wijzigen via Instellingen &gt; Toegankelijkheid."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Snelkoppeling voor <xliff:g id="SERVICE">%1$s</xliff:g> aanzetten?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Als je beide volumetoetsen een paar seconden ingedrukt houdt, wordt de toegankelijkheidsfunctie <xliff:g id="SERVICE">%1$s</xliff:g> aangezet. Hierdoor kan de manier veranderen waarop je apparaat werkt.\n\nJe kunt deze sneltoets op een andere functie instellen via Instellingen &gt; Toegankelijkheid."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aanzetten"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 7d27d4e..14ca2e5 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ଫେସ୍ ଅନଲକ୍"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ଫେସ୍ ଅନଲକ୍ ସହ ସମସ୍ୟା"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଚେହେରା କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ଫେସ୍ ଆଇକନ୍"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ସିଙ୍କ ସେଟିଙ୍ଗକୁ ପଢ଼ନ୍ତୁ"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ଏକ ଆକାଉଣ୍ଟ ପାଇଁ ସିଙ୍କ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ୍‍ଟିକୁ ଅନୁମତି ଦିଏ। ଉଦାହରଣସ୍ୱରୂପ, ଲୋକଙ୍କ ଆପ୍‍ ଏକ ଆକାଉଣ୍ଟରେ ସିଙ୍କ ହୋଇଛି କି ନାହିଁ ଏହା ଜାଣିପାରେ।"</string>
@@ -1038,9 +1042,9 @@
     <string name="menu_space_shortcut_label" msgid="5949311515646872071">"ସ୍ପେସ୍‍"</string>
     <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"ଏଣ୍ଟର୍"</string>
     <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"ଡିଲିଟ୍‌ କରନ୍ତୁ"</string>
-    <string name="search_go" msgid="2141477624421347086">"Search"</string>
-    <string name="search_hint" msgid="455364685740251925">"ସର୍ଚ୍ଚ…"</string>
-    <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+    <string name="search_go" msgid="2141477624421347086">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
+    <string name="search_hint" msgid="455364685740251925">"ସନ୍ଧାନ…"</string>
+    <string name="searchview_description_search" msgid="1045552007537359343">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="searchview_description_query" msgid="7430242366971716338">"କ୍ୱେରୀ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"କ୍ୱେରୀ ଖାଲି କରନ୍ତୁ"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"କ୍ୱେରୀ ଦାଖଲ କରନ୍ତୁ"</string>
@@ -1468,7 +1472,7 @@
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ଜୁମ୍ ନିୟନ୍ତ୍ରଣ ପାଇଁ ଦୁଇଥର ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="gadget_host_error_inflating" msgid="2449961590495198720">"ୱିଜେଟ୍‍ ଯୋଡ଼ିପାରିବ ନାହିଁ।"</string>
     <string name="ime_action_go" msgid="5536744546326495436">"ଯାଆନ୍ତୁ"</string>
-    <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+    <string name="ime_action_search" msgid="4501435960587287668">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="ime_action_send" msgid="8456843745664334138">"ପଠାନ୍ତୁ"</string>
     <string name="ime_action_next" msgid="4169702997635728543">"ପରବର୍ତ୍ତୀ"</string>
     <string name="ime_action_done" msgid="6299921014822891569">"ହୋଇଗଲା"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ସର୍ଟକଟ୍ ଚାଲୁ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଏକ ଆକ୍ସେସବିଲିଟି ଫିଚର୍ ଆରମ୍ଭ ହେବ।"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକ ପାଇଁ ସର୍ଟକଟ୍ ଚାଲୁ କରିବେ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକ ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nବର୍ତ୍ତମାନର ଫିଚରଗୁଡ଼ିକ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n ଆପଣ ସେଟିଂସ୍ &amp;gt ଆକ୍ସେସିବିଲିଟୀରେ ଚୟନିତ ଫିଚରଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ସର୍ଟକଟ୍ ଚାଲୁ କରିବେ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଏକ ଆକ୍ସେସିବିଲିଟୀ ଫିଚର୍ <xliff:g id="SERVICE">%1$s</xliff:g> ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nଆପଣ ସେଟିଂସ୍ &amp;gt ଆକ୍ସେସିବିଲିଟୀରେ ଏହି ସର୍ଚକଟକୁ ଅନ୍ୟ ଏକ ଫିଚରରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ଚାଲୁ କରନ୍ତୁ"</string>
@@ -1973,7 +1978,7 @@
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"ପ୍ରସ୍ତାବିତ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ସମସ୍ତ ଭାଷା"</string>
     <string name="region_picker_section_all" msgid="756441309928774155">"ସମସ୍ତ ଅଞ୍ଚଳ"</string>
-    <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+    <string name="locale_search_menu" msgid="6258090710176422934">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="app_suspended_title" msgid="888873445010322650">"ଆପ୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="app_suspended_default_message" msgid="6451215678552004172">"ବର୍ତ୍ତମାନ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ। ଏହା <xliff:g id="APP_NAME_1">%2$s</xliff:g> ଦ୍ଵାରା ପରିଚାଳିତ ହେଉଛି।"</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 12bf1bb..b9e2a0b 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -306,7 +306,7 @@
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"ਟਿਕਾਣਾ"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"ਇਸ ਡੀਵਾਈਸ ਦੇ ਨਿਰਧਾਰਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚੋ"</string>
-    <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+    <string name="permgrouplab_calendar" msgid="6426860926123033230">"ਕੈਲੰਡਰ"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਦੇਖੋ"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਤੀਕ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ਫ਼ੇਸ ਅਣਲਾਕ"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ਫ਼ੇਸ ਅਣਲਾਕ ਨਾਲ ਸਮੱਸਿਆ"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਚਿਹਰਾ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹੋ"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਹ ਪਤਾ ਕਰ ਸਕਦਾ ਹੈ ਕਿ People ਐਪ ਦਾ ਕਿਸੇ ਖਾਤੇ ਨਾਲ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
@@ -815,7 +819,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ਕੰਮ ਦਾ ਮੋਬਾਈਲ"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"ਦਫ਼ਤਰ ਦਾ ਪੇਜਰ"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"ਸਹਾਇਕ"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"ਵਿਉਂਂਤੀ"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"ਜਨਮਦਿਨ"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਲਈ ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ਕੁਝ ਸਕਿੰਟਾਂ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਨੂੰ ਦਬਾਈ ਰੱਖਣਾ, ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਤਰੀਕੇ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ।\n\nਮੌਜੂਦਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nਸੈਟਿੰਗਾਂ ਅਤੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਤੁਸੀਂ ਚੁਣੀਆਂ ਗਈਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ਕੀ <xliff:g id="SERVICE">%1$s</xliff:g> ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ਕੁਝ ਸਕਿੰਟਾਂ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਨੂੰ ਦਬਾਈ ਰੱਖਣਾ <xliff:g id="SERVICE">%1$s</xliff:g>, ਇੱਕ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਚਾਲੂ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਤਰੀਕੇ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ।\n\nਸੈਟਿੰਗਾਂ ਅਤੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਤੁਸੀਂ ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਕਿਸੇ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ਚਾਲੂ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 2b8076a..c3c30da1 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -333,7 +333,7 @@
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Czujniki na ciele"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"dostęp do danych czujnika podstawowych funkcji życiowych"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Pobieranie zawartości okna"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Sprawdzanie zawartości okna, z którego korzystasz."</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Sprawdzanie zawartości okna, z którego korzystasz."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Włączenie czytania dotykiem"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Klikane elementy będą wymawiane na głos, a ekran można przeglądać, używając gestów."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Obserwowanie wpisywanego tekstu"</string>
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aby kontynuować, użyj odcisku palca lub blokady ekranu"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odcisku palca"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Rozpoznawanie twarzy"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem z rozpoznawaniem twarzy"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aby kontynuować, użyj rozpoznawania twarzy lub blokady ekranu"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona twarzy"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"czytanie ustawień synchronizacji"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Zezwala aplikacji na odczyt ustawień synchronizacji konta. Pozwala to na przykład określić, czy aplikacja Ludzie jest zsynchronizowana z kontem."</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Gdy skrót jest włączony, jednoczesne naciskanie przez trzy sekundy obu przycisków głośności uruchamia funkcję ułatwień dostępu."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Włączyć skrót ułatwień dostępu?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza ułatwienia dostępu. Może to zmienić sposób działania urządzenia.\n\nBieżące funkcje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\naby zmienić wybrane funkcje, kliknij Ustawienia &gt; Ułatwienia dostępu."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Włączyć skrót <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza usługę <xliff:g id="SERVICE">%1$s</xliff:g>, stanowiącą ułatwienie dostępu. Może to zmienić sposób działania urządzenia.\n\nAby zmienić ten skrót i wskazać inną funkcję, kliknij Ustawienia &gt; Ułatwienia dostępu."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Włącz"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ab5f176..e5eb61d 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use sua impressão digital ou o bloqueio de tela para continuar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo deu errado. Tente de novo."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo deu errado. Tente de novo."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler as configurações de sincronização"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ativar atalho para recursos de acessibilidade?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter as duas teclas de volume pressionadas por alguns segundos ativa os recursos de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nRecursos atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÉ possível mudar os recursos selecionados em \"Config. &gt; Acessibilidade\"."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ativar atalho para <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter as duas teclas de volume pressionadas por alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, um recurso de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nÉ possível trocar o uso desse atalho para outro recurso em \"Config. &gt; Acessibilidade\"."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6455af0..cd4adb0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilize a impressão digital ou o bloqueio de ecrã para continuar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo correu mal. Tente novamente."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilize o rosto ou o bloqueio de ecrã para continuar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo correu mal. Tente novamente."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Ícone de rosto"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler definições de sincronização"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que a app leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a app Pessoas está sincronizada com uma conta."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Pretende ativar o atalho das funcionalidades de acessibilidade?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter premidas ambas as teclas de volume durante alguns segundos ativa as funcionalidades de acessibilidade. Estas podem alterar a forma como o seu dispositivo funciona.\n\nFuncionalidades atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\npode alterar as funcionalidades selecionadas em Definições &gt; Acessibilidade."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Pretende ativar o atalho do serviço <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter premidas ambas as teclas de volume durante alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, uma funcionalidade de acessibilidade. Esta pode alterar a forma como o seu dispositivo funciona.\n\nPode alterar este atalho para outra funcionalidade em Definições &gt; Acessibilidade."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ab5f176..e5eb61d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use sua impressão digital ou o bloqueio de tela para continuar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo deu errado. Tente de novo."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo deu errado. Tente de novo."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler as configurações de sincronização"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ativar atalho para recursos de acessibilidade?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter as duas teclas de volume pressionadas por alguns segundos ativa os recursos de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nRecursos atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÉ possível mudar os recursos selecionados em \"Config. &gt; Acessibilidade\"."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ativar atalho para <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter as duas teclas de volume pressionadas por alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, um recurso de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nÉ possível trocar o uso desse atalho para outro recurso em \"Config. &gt; Acessibilidade\"."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c20a590..71e338f 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -612,6 +612,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Folosiți amprenta sau blocarea ecranului pentru a continua"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Deblocare facială"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problemă cu Deblocarea facială"</string>
@@ -664,6 +666,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Folosiți-vă chipul sau blocarea ecranului pentru a continua"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Pictograma chip"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"citire setări sincronizare"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite aplicației să citească setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicația poate determina dacă aplicația Persoane este sincronizată cu un anumit cont."</string>
@@ -1714,7 +1718,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Atunci când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de trei secunde, veți lansa o funcție de accesibilitate."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activați comanda rapidă pentru funcțiile de accesibilitate?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Dacă apăsați ambele taste de volum câteva secunde, activați funcțiile de accesibilitate. Acest lucru poate schimba funcționarea dispozitivului.\n\nFuncțiile actuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuteți schimba funcțiile selectate din Setări &gt; Accesibilitate."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activați comanda rapidă <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Dacă apăsați ambele taste de volum câteva secunde, activați funcția de accesibilitate <xliff:g id="SERVICE">%1$s</xliff:g>. Acest lucru poate schimba funcționarea dispozitivului.\n\nPuteți alege altă funcție pentru această comandă în Setări &gt; Accesibilitate."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9c961ba..88d06f8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Чтобы продолжить, используйте отпечаток пальца или данные для разблокировки экрана."</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок отпечатка пальца"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейсконтроль"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Ошибка фейсконтроля"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Чтобы продолжить, посмотрите на экран или используйте данные для разблокировки."</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Значок лица"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"Просмотр настроек синхронизации"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте обе кнопки регулировки громкости в течение трех секунд."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Использовать быстрое включение?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Чтобы включить специальные возможности, нажмите обе кнопки регулировки громкости и удерживайте несколько секунд. Обратите внимание, что в работе устройства могут произойти изменения.\n\nТекущие функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nЧтобы изменить выбранные функции, перейдите в настройки и нажмите \"Специальные возможности\"."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Использовать быстрое включение сервиса \"<xliff:g id="SERVICE">%1$s</xliff:g>\"?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Чтобы включить функцию \"<xliff:g id="SERVICE">%1$s</xliff:g>\", нажмите обе кнопки регулировки громкости на несколько секунд. Обратите внимание, что в работе устройства могут произойти изменения.\n\nЧтобы назначить это сочетание клавиш другой функции, перейдите в настройки и выберите \"Специальные возможности\"."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Включить"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 2b20e66..1b7973d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ හෝ තිර අගුල භාවිත කරන්න"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ඇඟිලි සලකුණු නිරූපකය"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"මුහුණෙන් අගුළු හැරීම"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"මුහුණෙන් අගුලු හැරීම සම්බන්ධව ගැටලුවකි"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ඉදිරියට යාමට ඔබගේ මුහුණු හෝ තිර අගුල භාවිත කරන්න"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"මුහුණ නිරූපකය"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"සමමුහුර්ත සැකසීම් කියවන්න"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් කියවීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත දැයි මෙයට හඳුනා ගත හැක."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"කෙටිමග ක්‍රියාත්මක විට, හඬ පරිමා බොත්තම් දෙකම තත්පර 3ක් තිස්සේ එබීමෙන් ප්‍රවේශ්‍යතා විශේෂාංගය ආරම්භ වනු ඇත."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ප්‍රවේශ්‍යතා විශේෂාංග සඳහා කෙටි මග ක්‍රියාත්මක කරන්නද?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"හඬ පරිමා යතුරු දෙකම තත්පර කීපයකට පහළට අල්ලාගෙන සිටීම ප්‍රවේශ්‍යතා විශේෂාංග ක්‍රියාත්මක කරයි. මෙය ඔබේ උපාංගය ක්‍රියා කරන ආකාරය වෙනස් කළ හැකිය.\n\nවත්මන් විශේෂාංග:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nඔබට තේරූ විශේෂාංග සැකසීම් &gt; ප්‍රවේශ්‍යතාව හි වෙනස් කළ හැකිය."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> කෙටි මග ක්‍රියාත්මක කරන්නද?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"හඬ පරිමා යතුරු දෙකම තත්පර කීපයකට පහළට අල්ලාගෙන සිටීම ප්‍රවේශ්‍යතා විශේෂාංගයක් වන <xliff:g id="SERVICE">%1$s</xliff:g> ක්‍රියාත්මක කරයි. මෙය ඔබේ උපාංගය ක්‍රියා කරන ආකාරය වෙනස් කළ හැකිය.\n\nඔබට මෙම කෙටිමග සැකසීම් &gt; ප්‍රවේශ්‍යතාව හි තවත් විශේෂාංගයකට වෙනස් කළ හැකිය."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ක්‍රියාත්මක කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index cb18e2c..33ea9c9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -322,7 +322,7 @@
     <string name="permgroupdesc_microphone" msgid="1047786732792487722">"nahrávanie zvuku"</string>
     <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Fyzická aktivita"</string>
     <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"prístup k vašej fyzickej aktivite"</string>
-    <string name="permgrouplab_camera" msgid="9090413408963547706">"Fotoaparát"</string>
+    <string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"fotenie a natáčanie videí"</string>
     <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Zariadenia v okolí"</string>
     <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"objavovať a pripájať zariadenia v okolí"</string>
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Pokračujte použitím odtlačku prsta alebo zámky obrazovky"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odtlačku prsta"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odomknutie tvárou"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problém s odomknutím tvárou"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte použitím tváre alebo zámky obrazovky"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona tváre"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čítať nastavenia synchronizácie"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Chcete zapnúť skratku pre funkcie dostupnosti?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Pridržaním oboch tlačidiel hlasitosti na niekoľko sekúnd zapnete funkcie dostupnosti. Môže sa tým zmeniť spôsob fungovania vášho zariadenia.\n\nAktuálne funkcie:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVybrané funkcie môžete zmeniť v časti Nastavenia &gt; Dostupnosť."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Chcete zapnúť skratku na službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Pridržaním oboch klávesov hlasitosti na niekoľko sekúnd zapnete funkciu dostupnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Môže sa tým zmeniť spôsob fungovania vášho zariadenia.\n\nTúto skratku môžete zmeniť na inú funkciu v časti Nastavenia &gt; Dostupnosť."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Zapnúť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 414d0bd..f53d847b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -615,6 +615,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Za nadaljevanje uporabite prstni odtis ali odklepanje s poverilnico."</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona prstnih odtisov"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odklepanje z obrazom"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Težava z odklepanjem z obrazom"</string>
@@ -667,6 +669,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nadaljevanje uporabite obraz ali odklepanje s poverilnico."</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona obraza"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"branje nastavitev sinhronizacije"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Aplikaciji omogoča branje nastavitev sinhronizacije za račun. S tem lahko aplikacija na primer ugotovi, ali je aplikacija Ljudje sinhronizirana z računom."</string>
@@ -1736,7 +1740,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite vklopiti bližnjico za funkcije za ljudi s posebnimi potrebami?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Če za nekaj sekund pridržite obe tipki za glasnost, boste vklopili funkcije za ljudi s posebnimi potrebami. To lahko spremeni način delovanja naprave.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nIzbrane funkcije lahko spremenite v meniju »Nastavitve« &gt; »Funkcije za ljudi s posebnimi potrebami«."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite vklopiti bližnjico za <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Če za nekaj sekund pridržite obe tipki za glasnost, boste vklopili storitev <xliff:g id="SERVICE">%1$s</xliff:g>, ki je funkcija za ljudi s posebnimi potrebami. To lahko spremeni način delovanja naprave.\n\nTo bližnjico lahko v meniju »Nastavitve« &gt; »Funkcije za ljudi s posebnimi potrebami« spremenite, da bo uporabljena za drugo funkcijo."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Vklopi"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 16edb81..9cbc916 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Përdor gjurmën tënde të gishtit ose kyçjen e ekranit për të vazhduar"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona e gjurmës së gishtit"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Shkyçja me fytyrë"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem me \"Shkyçjen me fytyrë\""</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Përdor fytyrën tënde ose kyçjen e ekranit për të vazhduar"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ikona e fytyrës"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lexo cilësimet e sinkronizimit"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lejon aplikacionin të lexojë cilësimet e sinkronizimit për një llogari. Për shembull, kjo mund të përcaktojë nëse aplikacioni \"Kontaktet\" është i sinkronizuar me një llogari."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Të aktivizohet shkurtorja për veçoritë e qasshmërisë?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mbajtja shtypur e dy tasteve të volumit për pak sekonda aktivizon veçoritë e qasshmërisë. Kjo mund të ndryshojë mënyrën se si funksionon pajisja jote.\n\nVeçoritë aktuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nKe ndryshuar veçoritë e zgjedhura te Cilësimet &gt; Qasshmëria."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Të aktivizohet shkurtorja për <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mbajtja shtypur e dy tasteve të volumit për pak sekonda aktivizon <xliff:g id="SERVICE">%1$s</xliff:g>, një veçori të qasshmërisë. Kjo mund të ndryshojë mënyrën se si funksionon pajisja jote.\n\nMund të ndryshosh këtë shkurtore te një veçori tjetër te Cilësimet &gt; Qasshmëria."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivizo"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5261bd3..561f5a3 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -612,6 +612,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Користите отисак прста или закључавање екрана да бисте наставили"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона отиска прста"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Откључавање лицем"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем са откључавање лицем"</string>
@@ -664,6 +666,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користите лице или закључавање екрана да бисте наставили"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Икона лица"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"читање подешавања синхронизације"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дозвољава апликацији да чита подешавања синхронизације за налог. На пример, овако може да се утврди да ли је апликација Људи синхронизована са налогом."</string>
@@ -1714,7 +1718,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Желите да укључите пречицу за функције приступачности?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ако задржите оба тастера за јачину звука пар секунди, укључиће се функције приступачности. То може да промени начин рада уређаја.\n\nПостојеће функције:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМожете да промените изабране функције у одељку Подешавања &gt; Приступачност."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Желите да укључите пречицу за услугу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ако задржите оба тастера за јачину звука пар секунди, укључује се <xliff:g id="SERVICE">%1$s</xliff:g>, функција приступачности. То може да промени начин рада уређаја.\n\nМожете да промените функцију на коју се односи ова пречица у одељку Подешавања &gt; Приступачност."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Укључи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e494ef0..72c8ccc 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Fortsätt med hjälp av ditt fingeravtryck eller skärmlåset"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon för fingeravtryck"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansiktslås"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem med ansiktslås"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Fortsätt med hjälp av ditt ansikte eller skärmlåset"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Ansikte"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"läsa synkroniseringsinställningar"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tillåter att appen läser synkroniseringsinställningarna för ett konto. Detta kan användas till exempel för att avgöra om appen Personer är synkroniserad med ett konto."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vill du aktivera genvägen till tillgänglighetsfunktioner?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Om du trycker ned båda volymknapparna i ett par sekunder aktiveras tillgänglighetsfunktionerna. Det kan få enheten ett fungera annorlunda.\n\nAktuella funktioner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan ändra vilka funktioner som aktiveras under Inställningar &gt; Tillgänglighet."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vill du aktivera genvägen till <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Om du trycker ned båda volymknapparna i ett par sekunder aktiveras <xliff:g id="SERVICE">%1$s</xliff:g>, en tillgänglighetsfunktion. Det kan leda till att enheten fungerar annorlunda.\n\nDu kan ändra vilken funktion som ska aktiveras med genvägen under Inställningar &gt; Tillgänglighet."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivera"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4166478..90bdf85 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Tumia alama ya kidole au mbinu yako ya kufunga skrini ili uendelee"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Aikoni ya alama ya kidole"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Kufungua kwa Uso"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Hitilafu imetokea kwenye kipengele cha Kufungua kwa Uso"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Tumia uso au mbinu yako ya kufunga skrini ili uendelee"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Aikoni ya uso"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"kusoma mipangilio ya usawazishaji"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa sekunde tatu itafungua kipengele cha ufikivu."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ungependa kuwasha njia ya mkato ya vipengele vya ufikivu?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hatua ya kushikilia chini vitufe vyote viwili vya sauti kwa sekunde chache huwasha vipengele vya ufikivu. Huenda hatua hii ikabadilisha jinsi kifaa chako kinavyofanya kazi.\n\nVipengele vya sasa:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nUnaweza kubadilisha vipengele ulivyochagua katika Mipangilio &gt; Ufikivu."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ungependa kuwasha njia ya mkato ya <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hatua ya kushikilia chini vitufe vyote viwili vya sauti kwa sekunde chache huwasha <xliff:g id="SERVICE">%1$s</xliff:g>, kipengele cha ufikivu. Huenda hatua hii ikabadilisha jinsi kifaa chako kinavyofanya kazi.\n\nUnaweza kubadilisha njia hii ya mkato iwe kipengele kingine katika Mipangilio &gt; Ufikivu."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Washa"</string>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 34b6a54..861e329 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -51,5 +51,10 @@
 
     <!-- If true, show multiuser switcher by default unless the user specifically disables it. -->
     <bool name="config_showUserSwitcherByDefault">true</bool>
+
+    <!-- Enable dynamic keyguard positioning for large-width screens. This will cause the keyguard
+         to be aligned to one side of the screen when in landscape mode. -->
+    <bool name="config_enableDynamicKeyguardPositioning">true</bool>
+
 </resources>
 
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 63a5805..62fb2a0 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"TTY Mode HCOஐ இணைச் செயல்பாடு கோரியது"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"TTY Mode VCOஐ இணைச் செயல்பாடு கோரியது"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"TTY Mode OFFஐ இணைச் செயல்பாடு கோரியது"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"குரல்"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"தரவு"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"தொலைநகல்"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -169,7 +169,7 @@
     <string name="httpErrorUnsupportedScheme" msgid="2664108769858966374">"நெறிமுறை ஆதரிக்கப்படவில்லை."</string>
     <string name="httpErrorFailedSslHandshake" msgid="546319061228876290">"பாதுகாப்பான இணைப்பை நிறுவ முடியவில்லை."</string>
     <string name="httpErrorBadUrl" msgid="754447723314832538">"URL தவறாக உள்ளதால் பக்கத்தைத் திறக்க முடியவில்லை."</string>
-    <string name="httpErrorFile" msgid="3400658466057744084">"கோப்பை அணுக முடியவில்லை."</string>
+    <string name="httpErrorFile" msgid="3400658466057744084">"ஃபைலை அணுக முடியவில்லை."</string>
     <string name="httpErrorFileNotFound" msgid="5191433324871147386">"கோரப்பட்ட கோப்பைக் கண்டறிய முடியவில்லை."</string>
     <string name="httpErrorTooManyRequests" msgid="2149677715552037198">"மிக அதிகமான கோரிக்கைகள் செயல்படுத்தப்படுகின்றன. பிறகு முயற்சிக்கவும்."</string>
     <string name="notification_title" msgid="5783748077084481121">"<xliff:g id="ACCOUNT">%1$s</xliff:g> க்கான உள்நுழைவு பிழை"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"தொடர, உங்கள் கைரேகையையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"கைரேகை ஐகான்"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"முகம் காட்டித் திறத்தல்"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"முகம் காட்டித் திறத்தல் அம்சத்தில் சிக்கல்"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"தொடர, உங்கள் முகத்தையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"முக ஐகான்"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ஒத்திசைவு அமைப்புகளைப் படித்தல்"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"கணக்கிற்கான ஒத்திசைவு அமைப்புகளைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. எடுத்துக்காட்டாக, பீப்பிள் ஆப்ஸ் கணக்குடன் ஒத்திசைக்கப்பட்டுள்ளதா என்பதை இது தீர்மானிக்கலாம்."</string>
@@ -815,7 +819,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"பணியிட மொபைல்"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"பணியிட பேஜர்"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"உதவியாளர்"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"பிரத்தியேகம்"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"பிறந்தநாள்"</string>
@@ -848,7 +852,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"மற்றவை"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"பிரத்தியேகம்"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"பிரத்தியேகம்"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"உதவியாளர்"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"சகோதரர்"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"குழந்தை"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"வாழ்வுத் துணை"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ஷார்ட்கட் இயக்கத்தில் இருக்கும்போது ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு அழுத்தினால் அணுகல்தன்மை அம்சம் இயக்கப்படும்."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"அணுகல்தன்மை அம்சங்களுக்கான ஷார்ட்கட்டை ஆன் செய்யவா?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருந்தால் அணுகல்தன்மை அம்சங்கள் ஆன் செய்யப்படும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nதற்போதைய அம்சங்கள்:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nதேர்ந்தெடுத்த அம்சங்களை அமைப்புகள் &gt; அணுகல்தன்மைக்குச் சென்று உங்களால் மாற்ற முடியும்."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> அம்சத்துக்கான ஷார்ட்கட்டை ஆன் செய்யவா?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் அணுகல்தன்மை அம்சமான <xliff:g id="SERVICE">%1$s</xliff:g> ஆன் ஆகும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nஅமைப்புகள் &gt; அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ஆன் செய்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2a619e1..ef5c621 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -68,13 +68,13 @@
     <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>
-    <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"కాలర్ ID డిఫాల్ట్‌గా పరిమితానికి ఉంటుంది. తర్వాత కాల్: అపరిమితం"</string>
-    <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"కాలర్ ID డిఫాల్ట్‌గా అపరిమితానికి ఉంటుంది. తర్వాత కాల్: పరిమితం చేయబడింది"</string>
-    <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"కాలర్ ID డిఫాల్ట్‌గా అపరిమితానికి ఉంటుంది. తర్వాత కాల్: అపరిమితం"</string>
+    <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"కాలర్ ID ఆటోమేటిక్‌లపై పరిమితి ఉంటుంది. తర్వాత కాల్: పరిమితి ఉంటుంది"</string>
+    <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"కాలర్ ID ఆటోమేటిక్‌లపై పరిమితి ఉంటుంది. తర్వాత కాల్: పరిమితి లేదు"</string>
+    <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"కాలర్ ID ఆటోమేటిక్‌లపై పరిమితి లేదు. తర్వాత కాల్: పరిమితి ఉంటుంది"</string>
+    <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"కాలర్ ID ఆటోమేటిక్‌లపై పరిమితి లేదు. తర్వాత కాల్: పరిమితి లేదు"</string>
     <string name="serviceNotProvisioned" msgid="8289333510236766193">"సేవ కేటాయించబడలేదు."</string>
     <string name="CLIRPermanent" msgid="166443681876381118">"మీరు కాలర్ ID సెట్టింగ్‌ను మార్చలేరు."</string>
     <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"మొబైల్ డేటా సేవ లేదు"</string>
@@ -82,17 +82,17 @@
     <string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"వాయిస్ సేవ లేదు"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"వాయిస్ సేవ లేదా అత్యవసర కాలింగ్ లేదు"</string>
     <string name="RestrictedStateContent" msgid="7693575344608618926">"మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేయబడింది"</string>
-    <string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> కోసం మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేసారు"</string>
+    <string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> కోసం మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేశారు"</string>
     <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="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>
-    <string name="notification_channel_sms" msgid="1243384981025535724">"SMS సందేశాలు"</string>
-    <string name="notification_channel_voice_mail" msgid="8457433203106654172">"వాయిస్ మెయిల్ సందేశాలు"</string>
+    <string name="notification_channel_sms" msgid="1243384981025535724">"SMS మెసేజ్‌లు"</string>
+    <string name="notification_channel_voice_mail" msgid="8457433203106654172">"వాయిస్ మెయిల్ మెసేజ్‌లు"</string>
     <string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi కాలింగ్"</string>
     <string name="notification_channel_sim" msgid="5098802350325677490">"SIM స్టేటస్"</string>
     <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string>
@@ -100,12 +100,12 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"అవతలి వారు HCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"అవతలి వారు VCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"అవతలి వారు OFF TTY మోడ్‌ని అభ్యర్థించారు"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"వాయిస్"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"డేటా"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ఫ్యాక్స్"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
     <string name="serviceClassDataAsync" msgid="2029856900898545984">"నిరర్థకం"</string>
-    <string name="serviceClassDataSync" msgid="7895071363569133704">"సమకాలీకరణ"</string>
+    <string name="serviceClassDataSync" msgid="7895071363569133704">"సింక్‌"</string>
     <string name="serviceClassPacket" msgid="1430642951399303804">"ప్యాకెట్"</string>
     <string name="serviceClassPAD" msgid="6850244583416306321">"PAD"</string>
     <string name="roamingText0" msgid="7793257871609854208">"రోమింగ్ సూచిక ఆన్‌లో ఉంది"</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>
@@ -171,15 +171,15 @@
     <string name="httpErrorBadUrl" msgid="754447723314832538">"URL చెల్లనిది అయినందువలన పేజీని తెరవడం సాధ్యపడలేదు."</string>
     <string name="httpErrorFile" msgid="3400658466057744084">"ఫైల్‌ను యాక్సెస్ చేయడం సాధ్యపడలేదు."</string>
     <string name="httpErrorFileNotFound" msgid="5191433324871147386">"అభ్యర్థించిన ఫైల్‌ను కనుగొనడం సాధ్యపడలేదు."</string>
-    <string name="httpErrorTooManyRequests" msgid="2149677715552037198">"చాలా ఎక్కువ అభ్యర్థనలు ప్రాసెస్ చేయబడుతున్నాయి. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+    <string name="httpErrorTooManyRequests" msgid="2149677715552037198">"చాలా ఎక్కువ రిక్వెస్ట్‌లు ప్రాసెస్ చేయబడుతున్నాయి. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
     <string name="notification_title" msgid="5783748077084481121">"<xliff:g id="ACCOUNT">%1$s</xliff:g>కు సైన్‌ఇన్ ఎర్రర్"</string>
-    <string name="contentServiceSync" msgid="2341041749565687871">"సమకాలీకరణ"</string>
+    <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>
@@ -190,7 +190,7 @@
     <string name="work_profile_deleted" msgid="5891181538182009328">"కార్యాలయ ప్రొఫైల్ తొలగించబడింది"</string>
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"కార్యాలయ ప్రొఫైల్ నిర్వాహక యాప్ లేదు లేదా పాడైంది. తత్ఫలితంగా, మీ కార్యాలయ ప్రొఫైల్ మరియు సంబంధిత డేటా తొలగించబడ్డాయి. సహాయం కోసం మీ నిర్వాహకులను సంప్రదించండి."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ఈ పరికరంలో మీ కార్యాలయ ప్రొఫైల్ ఇప్పుడు అందుబాటులో లేదు"</string>
-    <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్‌వర్డ్ ప్రయత్నాలు చేసారు"</string>
+    <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్‌వర్డ్ ప్రయత్నాలు చేశారు"</string>
     <string name="device_ownership_relinquished" msgid="4080886992183195724">"వ్యక్తిగత వినియోగం కోసం నిర్వాహకులు పరికరాన్ని తీసి వేశారు"</string>
     <string name="network_logging_notification_title" msgid="554983187553845004">"పరికరం నిర్వహించబడింది"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"మీ సంస్థ ఈ పరికరాన్ని నిర్వహిస్తుంది మరియు నెట్‌వర్క్ ట్రాఫిక్‌ని పర్యవేక్షించవచ్చు. వివరాల కోసం నొక్కండి."</string>
@@ -247,21 +247,21 @@
     <string name="global_action_power_options" msgid="1185286119330160073">"పవర్"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"రీస్టార్ట్ చేయి"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"ఎమర్జెన్సీ"</string>
-    <string name="global_action_bug_report" msgid="5127867163044170003">"బగ్ నివేదిక"</string>
+    <string name="global_action_bug_report" msgid="5127867163044170003">"బగ్ రిపోర్ట్‌"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"సెషన్‌ను ముగించు"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"స్క్రీన్‌షాట్"</string>
     <string name="bugreport_title" msgid="8549990811777373050">"బగ్ రిపోర్ట్‌"</string>
-    <string name="bugreport_message" msgid="5212529146119624326">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
-    <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ప్రభావశీల నివేదిక"</string>
-    <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"చాలా సందర్భాల్లో దీన్ని ఉపయోగించండి. ఇది నివేదిక ప్రోగ్రెస్‌ను ట్రాక్ చేయడానికి, సమస్య గురించి మరిన్ని వివరాలను నమోదు చేయడానికి మరియు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతిస్తుంది. ఇది నివేదించడానికి ఎక్కువ సమయం పట్టే తక్కువ వినియోగ విభాగాలను విడిచిపెట్టవచ్చు."</string>
-    <string name="bugreport_option_full_title" msgid="7681035745950045690">"పూర్తి నివేదిక"</string>
-    <string name="bugreport_option_full_summary" msgid="1975130009258435885">"మీ పరికరం ప్రతిస్పందనరహితంగా ఉన్నప్పుడు లేదా చాలా నెమ్మదిగా ఉన్నప్పుడు లేదా మీకు అన్ని నివేదిక విభాగాలు అవసరమైనప్పుడు సిస్టమ్‌కి అంతరాయ స్థాయి కనిష్టంగా ఉండేలా చేయడానికి ఈ ఎంపిక ఉపయోగించండి. ఇది మరిన్ని వివరాలను నమోదు చేయడానికి లేదా అదనపు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతించదు."</string>
+    <string name="bugreport_message" msgid="5212529146119624326">"ఇది ఇ-మెయిల్ మెసేజ్‌ రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ రిపోర్ట్‌ను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
+    <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ప్రభావశీల రిపోర్ట్‌"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"చాలా సందర్భాల్లో దీన్ని ఉపయోగించండి. ఇది రిపోర్ట్‌ ప్రోగ్రెస్‌ను ట్రాక్ చేయడానికి, సమస్య గురించి మరిన్ని వివరాలను నమోదు చేయడానికి మరియు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతిస్తుంది. ఇది నివేదించడానికి ఎక్కువ సమయం పట్టే తక్కువ వినియోగ విభాగాలను విడిచిపెట్టవచ్చు."</string>
+    <string name="bugreport_option_full_title" msgid="7681035745950045690">"పూర్తి రిపోర్ట్‌"</string>
+    <string name="bugreport_option_full_summary" msgid="1975130009258435885">"మీ పరికరం ప్రతిస్పందనరహితంగా ఉన్నప్పుడు లేదా చాలా నెమ్మదిగా ఉన్నప్పుడు లేదా మీకు అన్ని రిపోర్ట్‌ విభాగాలు అవసరమైనప్పుడు సిస్టమ్‌కి అంతరాయ స్థాయి కనిష్టంగా ఉండేలా చేయడానికి ఈ ఎంపిక ఉపయోగించండి. ఇది మరిన్ని వివరాలను నమోదు చేయడానికి లేదా అదనపు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతించదు."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="3906120379260059206">
-      <item quantity="other">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
-      <item quantity="one">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_0">%d</xliff:g> సెకనులో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
+      <item quantity="other">బగ్ రిపోర్ట్‌ కోసం <xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
+      <item quantity="one">బగ్ రిపోర్ట్‌ కోసం <xliff:g id="NUMBER_0">%d</xliff:g> సెకనులో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
     </plurals>
-    <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"బగ్ నివేదికతో ఉన్న స్క్రీన్‌షాట్ తీయబడింది"</string>
-    <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"బగ్ నివేదికతో ఉన్న స్క్రీన్‌షాట్‌ను తీయడం విఫలమైంది"</string>
+    <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"బగ్ రిపోర్ట్‌తో ఉన్న స్క్రీన్‌షాట్ తీయబడింది"</string>
+    <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"బగ్ రిపోర్ట్‌తో ఉన్న స్క్రీన్‌షాట్‌ను తీయడం విఫలమైంది"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"నిశ్శబ్ద మోడ్"</string>
     <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ధ్వని ఆఫ్‌లో ఉంది"</string>
     <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ధ్వని ఆన్‌లో ఉంది"</string>
@@ -279,8 +279,8 @@
     <string name="notification_channel_security" msgid="8516754650348238057">"సెక్యూరిటీ"</string>
     <string name="notification_channel_car_mode" msgid="2123919247040988436">"కార్‌ మోడ్"</string>
     <string name="notification_channel_account" msgid="6436294521740148173">"ఖాతా స్థితి"</string>
-    <string name="notification_channel_developer" msgid="1691059964407549150">"డెవలపర్ సందేశాలు"</string>
-    <string name="notification_channel_developer_important" msgid="7197281908918789589">"ముఖ్యమైన డెవలపర్ సందేశాలు"</string>
+    <string name="notification_channel_developer" msgid="1691059964407549150">"డెవలపర్ మెసేజ్‌లు"</string>
+    <string name="notification_channel_developer_important" msgid="7197281908918789589">"ముఖ్యమైన డెవలపర్ మెసేజ్‌లు"</string>
     <string name="notification_channel_updates" msgid="7907863984825495278">"అప్‌డేట్‌లు"</string>
     <string name="notification_channel_network_status" msgid="2127687368725272809">"నెట్‌వర్క్ స్థితి"</string>
     <string name="notification_channel_network_alerts" msgid="6312366315654526528">"నెట్‌వర్క్ హెచ్చరికలు"</string>
@@ -305,17 +305,17 @@
     <string name="permgrouplab_contacts" msgid="4254143639307316920">"కాంటాక్ట్‌లు"</string>
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ కాంటాక్ట్‌లను యాక్సెస్ చేయడానికి"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"లొకేషన్"</string>
-    <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string>
-    <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+    <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర లొకేషన్‌ను యాక్సెస్ చేయడానికి"</string>
+    <string name="permgrouplab_calendar" msgid="6426860926123033230">"క్యాలెండర్"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్‌ను యాక్సెస్ చేయడానికి"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="5726462398070064542">"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>
-    <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"భౌతిక కార్యకలాపాన్ని యాక్సెస్ చేయండి"</string>
+    <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"భౌతిక యాక్టివిటీని యాక్సెస్ చేయండి"</string>
     <string name="permgrouplab_camera" msgid="9090413408963547706">"కెమెరా"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"చిత్రాలను తీయడానికి మరియు వీడియోను రికార్డ్ చేయడానికి"</string>
     <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"సమీపంలోని పరికరాలు"</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>
@@ -349,42 +349,42 @@
     <string name="permlab_fullScreenIntent" msgid="4310888199502509104">"లాక్ చేసి ఉన్న పరికరంలో నోటిఫికేషన్‌లను ఫుల్ స్క్రీన్ యాక్టివిటీలుగా డిస్‌ప్లే చేస్తుంది"</string>
     <string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"లాక్ చేసి ఉన్న పరికరంలో నోటిఫికేషన్‌లను ఫుల్ స్క్రీన్ యాక్టివిటీలుగా డిస్‌ప్లే చేయడానికి యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="permlab_install_shortcut" msgid="7451554307502256221">"షార్ట్‌కట్‌లను ఇన్‌స్టాల్ చేయడం"</string>
-    <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="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="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్‌ను వేరే నంబర్‌కు దారి మళ్లించే లేదా మొత్తంగా కాల్‌ను ఆపివేసే ఎంపిక సహాయంతో అవుట్‌గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్‌ను చూడటానికి యాప్‌ను అనుమతిస్తుంది."</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>
-    <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
-    <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార సందేశాలను ఫార్వర్డ్ చేయడం"</string>
-    <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార సందేశాలను అందుకుంటే, వాటిని ఫార్వర్డ్ చేసే విధంగా సెల్ ప్రసార మాడ్యూల్‌కు కట్టుబడి ఉండటానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం అందుకున్నప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</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>
+    <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS మెసేజ్‌లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన మెసేజ్‌లను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
+    <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార మెసేజ్‌లను ఫార్వర్డ్ చేయడం"</string>
+    <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్‌లను అందుకుంటే, వాటిని ఫార్వర్డ్ చేసే విధంగా సెల్ ప్రసార మాడ్యూల్‌కు కట్టుబడి ఉండటానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం అందుకున్నప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్‌ను మేనేజ్ చేయి"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"మీ పరికరంలో కొనసాగుతున్న కాల్స్‌ను చూడటానికి అలాగే వాటిని కంట్రోల్ చేయడానికి ఒక యాప్‌కు అనుమతిస్తోంది."</string>
-    <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార సందేశాలను చదవడం"</string>
-    <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార సందేశాలను చదవడానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం స్వీకరించినప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
+    <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార మెసేజ్‌లను చదవడం"</string>
+    <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం స్వీకరించినప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"చందా చేయబడిన ఫీడ్‌లను చదవడం"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"ప్రస్తుతం సమకాలీకరించిన ఫీడ్‌ల గురించి వివరాలను పొందడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_sendSms" msgid="7757368721742014252">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string>
-    <string name="permdesc_sendSms" msgid="6757089798435130769">"SMS సందేశాలు పంపడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన ఊహించని ఛార్జీలు విధించబడవచ్చు. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే సందేశాలను పంపడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
-    <string name="permlab_readSms" msgid="5164176626258800297">"మీ వచన సందేశాలు (SMS లేదా MMS) చదవడం"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ఈ యాప్‌ మీ టాబ్లెట్‌లో నిల్వ చేసిన అన్ని SMS (వచన) సందేశాలను చదవగలదు."</string>
+    <string name="permlab_sendSms" msgid="7757368721742014252">"SMS మెసేజ్‌లను పంపడం మరియు వీక్షించడం"</string>
+    <string name="permdesc_sendSms" msgid="6757089798435130769">"SMS మెసేజ్‌లు పంపడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన ఊహించని ఛార్జీలు విధించబడవచ్చు. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే మెసేజ్‌లను పంపడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
+    <string name="permlab_readSms" msgid="5164176626258800297">"మీ వచన మెసేజ్‌లు (SMS లేదా MMS) చదవడం"</string>
+    <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ఈ యాప్‌ మీ టాబ్లెట్‌లో నిల్వ చేసిన అన్ని SMS (వచన) మెసేజ్‌లను చదవగలదు."</string>
     <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"ఈ యాప్ మీ Android TV పరికరంలో నిల్వ అయిన SMS (వచనం) సందేశాలన్నింటినీ చదవగలదు."</string>
-    <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="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="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>
@@ -410,20 +410,20 @@
     <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"ప్రసారం ముగిసిన తర్వాత భద్రపరచబడే ప్రసారాలను పంపడానికి యాప్‌ను అనుమతిస్తుంది. అత్యధిక వినియోగం వలన టాబ్లెట్ నెమ్మదిగా పని చేయవచ్చు లేదా అధిక పరిమాణంలో మెమరీని ఉపయోగించడం వలన అస్థిరంగా మారవచ్చు."</string>
     <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"ప్రసారం ముగిసిన తర్వాత భద్రపరచబడే ప్రసారాలను పంపడానికి యాప్‌ని అనుమతిస్తుంది. ఎక్కువగా వినియోగిస్తే అధిక పరిమాణంలో మెమరీని ఉపయోగించడం వలన టీవీ నెమ్మదిగా పని చేయవచ్చు లేదా అస్థిరంగా మారవచ్చు."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"ప్రసారం ముగిసిన తర్వాత భద్రపరచబడే ప్రసారాలను పంపడానికి యాప్‌ను అనుమతిస్తుంది. అత్యధిక వినియోగం వలన ఫోన్ నెమ్మదిగా పని చేయవచ్చు లేదా అధిక పరిమాణంలో మెమరీని ఉపయోగించడం వలన అస్థిరంగా మారవచ్చు."</string>
-    <string name="permlab_readContacts" msgid="8776395111787429099">"మీ పరిచయాలను చదవడం"</string>
+    <string name="permlab_readContacts" msgid="8776395111787429099">"మీ కాంటాక్ట్‌లను చదవడం"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"టాబ్లెట్‌లో నిల్వ చేసిన మీ కాంటాక్ట్‌లకు సంబంధించిన డేటాను చదవడానికి యాప్‌ను అనుమతిస్తుంది. కాంటాక్ట్‌లను సృష్టించిన మీ టాబ్లెట్‌లోని ఖాతాలకు కూడా యాప్‌లకు యాక్సెస్ ఉంటుంది. ఇందులో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఉండవచ్చు. ఈ అనుమతి, మీ కాంటాక్ట్ డేటాను సేవ్ చేయడానికి యాప్‌లను అనుమతిస్తుంది, హానికరమైన యాప్‌లు మీకు తెలియకుండానే కాంటాక్ట్ డేటాను షేర్ చేయవచ్చు."</string>
     <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"మీ Android TV పరికరంలో నిల్వ చేసిన కాంటాక్ట్‌లకు సంబంధించిన డేటాను చదవడానికి యాప్‌ను అనుమతిస్తుంది. కాంటాక్ట్‌లను సృష్టించిన మీ Android TV పరికరంలోని ఖాతాలకు కూడా యాప్‌లకు యాక్సెస్ ఉంటుంది. ఇందులో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఉండవచ్చు. ఈ అనుమతి, మీ కాంటాక్ట్ డేటాను సేవ్ చేయడానికి యాప్‌లను అనుమతిస్తుంది, హానికరమైన యాప్‌లు మీకు తెలియకుండానే కాంటాక్ట్ డేటాను షేర్ చేయవచ్చు."</string>
     <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"ఫోన్‌లో నిల్వ చేసిన మీ కాంటాక్ట్‌లకు సంబంధించిన డేటాను చదవడానికి యాప్‌ను అనుమతిస్తుంది. కాంటాక్ట్‌లను సృష్టించిన మీ ఫోన్‌లోని ఖాతాలను కూడా యాప్‌లు యాక్సెస్ చేయగలవు. ఇందులో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఉండవచ్చు. ఈ అనుమతి, మీ కాంటాక్ట్ డేటాను సేవ్ చేయడానికి యాప్‌లను అనుమతిస్తుంది, హానికరమైన యాప్‌లు మీకు తెలియకుండానే కాంటాక్ట్ డేటాను షేర్ చేయవచ్చు."</string>
-    <string name="permlab_writeContacts" msgid="8919430536404830430">"మీ పరిచయాలను సవరించడం"</string>
+    <string name="permlab_writeContacts" msgid="8919430536404830430">"మీ కాంటాక్ట్‌లను సవరించడం"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"మీ టాబ్లెట్‌లో నిల్వ చేసి ఉన్న కాంటాక్ట్‌లకు సంబంధించిన డేటాను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి, కాంటాక్ట్ డేటాను తొలగించడానికి యాప్‌లను అనుమతిస్తుంది."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"మీ Android TV పరికరంలో నిల్వ చేసి ఉన్న కాంటాక్ట్‌లకు సంబంధించిన డేటాను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి, కాంటాక్ట్ డేటాను తొలగించడానికి యాప్‌లను అనుమతిస్తుంది."</string>
     <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"మీ ఫోన్‌లో నిల్వ చేసి ఉన్న కాంటాక్ట్‌లకు సంబంధించిన డేటాను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి, కాంటాక్ట్ డేటాను తొలగించడానికి యాప్‌లను అనుమతిస్తుంది."</string>
     <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>
@@ -431,16 +431,16 @@
     <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"ఈ యాప్‌ మీ Android TV పరికరంలో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్‌లన్నీ చదవగలదు, మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string>
     <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"ఈ యాప్ మీ ఫోన్‌లో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్‌లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string>
     <string name="permlab_writeCalendar" msgid="6422137308329578076">"యజమానికి తెలియకుండానే క్యాలెండర్ ఈవెంట్‌లను జోడించి లేదా సవరించి, అతిథులకు ఇమెయిల్ పంపడం"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
-    <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
-    <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడం"</string>
-    <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర స్థాన మూలాల నిర్వహణలో యాప్‌ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
-    <string name="permlab_accessFineLocation" msgid="6426318438195622966">"స్క్రీన్‌పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన స్థానాన్ని యాక్సెస్ చేయండి"</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్‌లను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
+    <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్‌లను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్‌లను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
+    <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"అదనపు లొకేషన్ ప్రొవైడర్ కమాండ్‌లను యాక్సెస్ చేయడం"</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"అదనపు లొకేషన్ ప్రొవైడర్ కమాండ్లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర లొకేషన్ సోర్స్‌ల నిర్వహణలో యాప్‌ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
+    <string name="permlab_accessFineLocation" msgid="6426318438195622966">"స్క్రీన్‌పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన లొకేషన్‌ను యాక్సెస్ చేయండి"</string>
     <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"యాప్ ఉపయోగంలో ఉన్నప్పుడు మాత్రమే ఈ యాప్ మీ ఖచ్చితమైన లొకేషన్‌ను లొకేషన్ సర్వీస్‌ల ద్వారా తెలుసుకోగలదు. లొకేషన్‌ను యాప్ పొందాలంటే, దాని కోసం మీ పరికరం యొక్క లొకేషన్ సర్వీస్‌లను తప్పనిసరిగా ఆన్ చేయాలి. ఇది బ్యాటరీ వినియోగాన్ని పెంచవచ్చు."</string>
     <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"స్క్రీన్‌పై ఉన్నప్పుడు మాత్రమే సుమారు లొకేషన్‌ను యాక్సెస్ చేయండి"</string>
     <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"యాప్ ఉపయోగంలో ఉన్నప్పుడు మాత్రమే ఈ యాప్ మీ ఇంచుమించు లొకేషన్‌ను లొకేషన్ సర్వీస్‌ల నుండి తెలుసుకోగలదు. లొకేషన్‌ను యాప్ పొందాలంటే, దాని కోసం మీ పరికరం యొక్క లొకేషన్ సర్వీస్‌లను తప్పనిసరిగా ఆన్ చేయాలి."</string>
-    <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"నేపథ్యంలో స్థానాన్ని యాక్సెస్ చేయి"</string>
+    <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"బ్యాక్‌గ్రౌండ్‌లో లొకేషన్‌ను యాక్సెస్ చేయి"</string>
     <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"యాప్ ఉపయోగంలో లేనప్పటికీ కూడా, ఈ యాప్, లొకేషన్‌ను ఎప్పుడైనా యాక్సెస్ చేయగలదు."</string>
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"మీ ఆడియో సెట్టింగ్‌లను మార్చడం"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"వాల్యూమ్ మరియు అవుట్‌పుట్ కోసం ఉపయోగించాల్సిన స్పీకర్ వంటి సార్వజనీన ఆడియో సెట్టింగ్‌లను సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</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>
@@ -500,9 +500,9 @@
     <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"మీ Android TV పరికరం సమయ మండలిని మార్చడానికి యాప్‌ని అనుమతిస్తుంది."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"ఫోన్ యొక్క సమయ మండలిని మార్చడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_getAccounts" msgid="5304317160463582791">"పరికరంలో ఖాతాలను కనుగొనడం"</string>
-    <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"టాబ్లెట్‌కు తెలిసిన ఖాతాల జాబితాను పొందడానికి యాప్‌ను అనుమతిస్తుంది. దీనిలో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఏవైనా ఉండవచ్చు."</string>
-    <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"మీ Android TV పరికరానికి తెలిసిన ఖాతాల జాబితాను పొందడానికి యాప్‌ను అనుమతిస్తుంది. దీనిలో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఏవైనా ఉండవచ్చు."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"ఫోన్‌కు తెలిసిన ఖాతాల జాబితాను పొందడానికి యాప్‌ను అనుమతిస్తుంది. దీనిలో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఏవైనా ఉండవచ్చు."</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"టాబ్లెట్‌కు తెలిసిన ఖాతాల లిస్ట్‌ను పొందడానికి యాప్‌ను అనుమతిస్తుంది. దీనిలో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఏవైనా ఉండవచ్చు."</string>
+    <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"మీ Android TV పరికరానికి తెలిసిన ఖాతాల లిస్ట్‌ను పొందడానికి యాప్‌ను అనుమతిస్తుంది. దీనిలో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఏవైనా ఉండవచ్చు."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"ఫోన్‌కు తెలిసిన ఖాతాల లిస్ట్‌ను పొందడానికి యాప్‌ను అనుమతిస్తుంది. దీనిలో మీరు ఇన్‌స్టాల్ చేసిన యాప్‌ల ద్వారా సృష్టించబడిన ఖాతాలు ఏవైనా ఉండవచ్చు."</string>
     <string name="permlab_accessNetworkState" msgid="2349126720783633918">"నెట్‌వర్క్ కనెక్షన్‌లను వీక్షించడం"</string>
     <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"ఏ నెట్‌వర్క్‌లు ఉన్నాయి మరియు కనెక్ట్ చేయబడ్డాయి వంటి నెట్‌వర్క్ కనెక్షన్‌ల గురించి సమాచారాన్ని వీక్షించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"నెట్‌వర్క్‌ను పూర్తిగా యాక్సెస్ చేయగలగడం"</string>
@@ -516,9 +516,9 @@
     <string name="permlab_changeWifiState" msgid="7947824109713181554">"Wi-Fiకి కనెక్ట్ చేయడం మరియు దాని నుండి డిస్‌కనెక్ట్ చేయడం"</string>
     <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Wi-Fi యాక్సెస్ స్థానాలకు కనెక్ట్ చేయడానికి మరియు వాటి నుండి డిస్‌కనెక్ట్ చేయడానికి మరియు Wi-Fi నెట్‌వర్క్‌ల కోసం పరికర కాన్ఫిగరేషన్‌కు మార్పులు చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"Wi-Fi Multicast స్వీకరణను అనుమతించడం"</string>
-    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ టాబ్లెట్‌కు మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ Android TV పరికరానికి మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ని అనుమతిస్తుంది. ఇది మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఎక్కువ పవర్‌ను ఉపయోగిస్తుంది."</string>
-    <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ ఫోన్‌కు మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"మల్టీక్యాస్ట్ అడ్రస్‌లను ఉపయోగించి మీ టాబ్లెట్‌కు మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"మల్టీక్యాస్ట్ అడ్రస్‌లను ఉపయోగించి మీ Android TV పరికరానికి మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ని అనుమతిస్తుంది. ఇది మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఎక్కువ పవర్‌ను ఉపయోగిస్తుంది."</string>
+    <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"మల్టీక్యాస్ట్ అడ్రస్‌లను ఉపయోగించి మీ ఫోన్‌కు మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
     <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"బ్లూటూత్ సెట్టింగ్‌లను యాక్సెస్ చేయడం"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"స్థానిక బ్లూటూత్ టాబ్లెట్‌ను కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలతో దాన్ని కనుగొనడానికి మరియు జత చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"మీ Android TV పరికరంలో బ్లూటూత్‌ను కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలతో దాన్ని కనుగొని, జత చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
@@ -547,7 +547,7 @@
     <string name="permdesc_nfc" msgid="8352737680695296741">"సమీప ఫీల్డ్ కమ్యూనికేషన్ (NFC) ట్యాగ్‌లు, కార్డులు మరియు రీడర్‌లతో కమ్యూనికేట్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_disableKeyguard" msgid="3605253559020928505">"మీ స్క్రీన్ లాక్‌ను నిలిపివేయడం"</string>
     <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"కీలాక్ మరియు ఏదైనా అనుబంధించబడిన పాస్‌వర్డ్ భద్రతను నిలిపివేయడానికి యాప్‌ను అనుమతిస్తుంది. ఉదాహరణకు, ఇన్‌కమింగ్ ఫోన్ కాల్ వస్తున్నప్పుడు ఫోన్ కీలాక్‌ను నిలిపివేస్తుంది, ఆపై కాల్ ముగిసిన తర్వాత కీలాక్‌ను మళ్లీ ప్రారంభిస్తుంది."</string>
-    <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"స్క్రీన్ లాక్ సంక్లిష్టత అభ్యర్థన"</string>
+    <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"స్క్రీన్ లాక్ సంక్లిష్టత రిక్వెస్ట్‌"</string>
     <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"ఇది మీ స్క్రీన్ లాక్ పాస్‌వర్డ్‌ సంక్లిష్టత స్థాయి (తీవ్రంగా ఉండాలా, ఓ మోస్తరుగా ఉండాలా, తక్కువ తీవ్రంగా ఉండాలా లేదా అస్సలు తీవ్రత ఉండకూడదా) తెలుసుకోవడానికి యాప్‌ను అనుమతిస్తుంది, అంటే పొడుగు ఎంత ఉండాలి, ఏ రకమైన స్క్రీన్ లాక్ పధ్ధతి అనుసరించాలో సూచిస్తుంది. అలాగే, స్క్రీన్ లాక్‌ పాస్‌వర్డ్‌ సంక్లిష్టతను ఏ స్థాయికి సెట్ చేసుకుంటే బాగుంటుందో కూడా వినియోగదారులకు యాప్ సూచించగలదు, కానీ వినియోగదారులు నిరభ్యంతరంగా ఆ సూచనలను పట్టించుకోకుండా వారి ఇష్టం మేరకు చక్కగా సెట్ చేసుకోవచ్చు. ఇంకో ముఖ్య విషయం, స్క్రీన్ లాక్‌ అన్నది సాదా వచన రూపంలో నిల్వ చేయబడదు, కనుక ఖచ్చితమైన పాస్‌వర్డ్‌ ఏమిటనేది యాప్‌కు తెలియదు."</string>
     <string name="permlab_useBiometric" msgid="6314741124749633786">"బయోమెట్రిక్ హార్డ్‌వేర్‌ని ఉపయోగించు"</string>
     <string name="permdesc_useBiometric" msgid="7502858732677143410">"ప్రమాణీకరణ కోసం బయోమెట్రిక్ హార్డ్‌వేర్‌ను ఉపయోగించడానికి యాప్‌ని అనుమతిస్తుంది"</string>
@@ -555,11 +555,11 @@
     <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"వినియోగం కోసం వేలిముద్ర టెంప్లేట్‌లను జోడించే, తొలగించే పద్ధతులను అమలు చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_useFingerprint" msgid="1001421069766751922">"వేలిముద్ర హార్డ్‌వేర్‌ని ఉపయోగించడానికి అనుమతి"</string>
     <string name="permdesc_useFingerprint" msgid="412463055059323742">"ప్రామాణీకరణ కోసం వేలిముద్ర హార్డ్‌వేర్‌ను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది"</string>
-    <string name="permlab_audioWrite" msgid="8501705294265669405">"మీ సంగీత సేకరణను సవరించండి"</string>
+    <string name="permlab_audioWrite" msgid="8501705294265669405">"మీ సంగీత సేకరణను ఎడిట్ చేయండి"</string>
     <string name="permdesc_audioWrite" msgid="8057399517013412431">"మీ సంగీత సేకరణని సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_videoWrite" msgid="5940738769586451318">"మీ వీడియో సేకరణను సవరించండి"</string>
+    <string name="permlab_videoWrite" msgid="5940738769586451318">"మీ వీడియో సేకరణను ఎడిట్ చేయండి"</string>
     <string name="permdesc_videoWrite" msgid="6124731210613317051">"మీ వీడియో సేకరణను సవరించడానికి యాప్‌ని అనుమతిస్తుంది."</string>
-    <string name="permlab_imagesWrite" msgid="1774555086984985578">"మీ ఫోటో సేకరణను సవరించండి"</string>
+    <string name="permlab_imagesWrite" msgid="1774555086984985578">"మీ ఫోటో సేకరణను ఎడిట్ చేయండి"</string>
     <string name="permdesc_imagesWrite" msgid="5195054463269193317">"మీ ఫోటో సేకరణను సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_mediaLocation" msgid="7368098373378598066">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string>
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
@@ -593,9 +593,9 @@
     <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"వేలిముద్ర హార్డ్‌వేర్ అందుబాటులో లేదు."</string>
     <string name="fingerprint_error_no_space" msgid="7285481581905967580">"వేలిముద్రను సెటప్ చేయడం సాధ్యం కాదు"</string>
     <string name="fingerprint_error_timeout" msgid="2946635815726054226">"వేలిముద్ర గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
-    <string name="fingerprint_error_canceled" msgid="540026881380070750">"వేలిముద్ర కార్యకలాపం రద్దయింది."</string>
-    <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేసారు."</string>
-    <string name="fingerprint_error_lockout" msgid="7853461265604738671">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+    <string name="fingerprint_error_canceled" msgid="540026881380070750">"వేలిముద్ర యాక్టివిటీ రద్దయింది."</string>
+    <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేశారు."</string>
+    <string name="fingerprint_error_lockout" msgid="7853461265604738671">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
     <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"అనేకసార్లు ప్రయత్నించారు. వేలిముద్ర సెన్సార్ నిలిపివేయబడింది."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"మళ్లీ ప్రయత్నించండి."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"కొనసాగించడానికి మీ వేలిముద్ర లేదా స్క్రీన్ లాక్‌ను ఉపయోగించండి"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ఫేస్ అన్‌లాక్"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ఫేస్ అన్‌లాక్‌తో సమస్య"</string>
@@ -645,9 +647,9 @@
     <string name="face_error_hw_not_available" msgid="5085202213036026288">"ముఖం ధృవీకరించలేరు. హార్డ్‌వేర్ అందుబాటులో లేదు."</string>
     <string name="face_error_timeout" msgid="2598544068593889762">"ఫేస్ అన్‌లాక్‌ను మళ్లీ ట్రై చేయండి"</string>
     <string name="face_error_no_space" msgid="5649264057026021723">"కొత్త ముఖం డేటాను నిల్వ చేయడం కాదు. మొదట పాతది తొలిగించండి."</string>
-    <string name="face_error_canceled" msgid="2164434737103802131">"ముఖ కార్యకలాపం రద్దయింది."</string>
+    <string name="face_error_canceled" msgid="2164434737103802131">"ముఖ యాక్టివిటీ రద్దయింది."</string>
     <string name="face_error_user_canceled" msgid="5766472033202928373">"ఫేస్ అన్‌లాక్‌ను యూజర్ రద్దు చేశారు"</string>
-    <string name="face_error_lockout" msgid="7864408714994529437">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+    <string name="face_error_lockout" msgid="7864408714994529437">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
     <string name="face_error_lockout_permanent" msgid="3277134834042995260">"చాలా ఎక్కువ సార్లు ప్రయత్నించారు. ఫేస్ అన్‌లాక్ డిజేబుల్ చేయబడింది."</string>
     <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"చాలా ఎక్కువ సార్లు ప్రయత్నించారు. బదులుగా స్క్రీన్ లాక్‌ను ఎంటర్ చేయండి."</string>
     <string name="face_error_unable_to_process" msgid="5723292697366130070">"ముఖం ధృవీకరించలేకపోయింది. మళ్లీ ప్రయత్నించండి."</string>
@@ -661,19 +663,21 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"కొనసాగించడానికి మీ ముఖం లేదా స్క్రీన్ లాక్‌ను ఉపయోగించండి"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ముఖ చిహ్నం"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"సింక్ సెట్టింగ్‌లను చదవగలగడం"</string>
-    <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ఖాతా యొక్క సమకాలీకరణ సెట్టింగ్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది. ఉదాహరణకు, వ్యక్తుల యాప్‌ ఖాతాతో సమకాలీకరించబడాలా లేదా అనే విషయాన్ని ఇది నిశ్చయించవచ్చు."</string>
+    <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ఖాతా యొక్క సింక్‌ సెట్టింగ్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది. ఉదాహరణకు, వ్యక్తుల యాప్‌ ఖాతాతో సమకాలీకరించబడాలా లేదా అనే విషయాన్ని ఇది నిశ్చయించవచ్చు."</string>
     <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"\'సింక్\'ను ఆన్, ఆఫ్‌ల మధ్య టోగుల్ చేయడం"</string>
-    <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"ఖాతా యొక్క సమకాలీకరణ సెట్టింగ్‌లను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఉదాహరణకు, ఇది ఒక ఖాతాతో వ్యక్తుల యాప్ యొక్క సమకాలీకరణను ప్రారంభించడానికి ఉపయోగించబడవచ్చు."</string>
+    <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"ఖాతా యొక్క సింక్‌ సెట్టింగ్‌లను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఉదాహరణకు, ఇది ఒక ఖాతాతో వ్యక్తుల యాప్ యొక్క సింక్‌ను ప్రారంభించడానికి ఉపయోగించబడవచ్చు."</string>
     <string name="permlab_readSyncStats" msgid="3747407238320105332">"సింక్ గణాంకాలను చదవగలగడం"</string>
-    <string name="permdesc_readSyncStats" msgid="3867809926567379434">"ఖాతా యొక్క సమకాలీకరణ గణాంకాలను అలాగే సమకాలీకరణ ఈవెంట్‌ల చరిత్రను మరియు ఎంత డేటా సమకాలీకరించబడింది అనేవాటిని చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permdesc_readSyncStats" msgid="3867809926567379434">"ఖాతా యొక్క సింక్‌ గణాంకాలను అలాగే సింక్‌ ఈవెంట్‌ల చరిత్రను మరియు ఎంత డేటా సమకాలీకరించబడింది అనేవాటిని చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_sdcardRead" msgid="5791467020950064920">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను చదువుతుంది"</string>
     <string name="permdesc_sdcardRead" msgid="6872973242228240382">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_sdcardWrite" msgid="4863021819671416668">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను సవరించండి లేదా తొలగించండి"</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 +687,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 +697,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>
@@ -848,7 +852,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"ఇతరం"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"అనుకూలం"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"అనుకూలం"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"అసిస్టెంట్"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"సోదరుడు"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"బిడ్డ"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"జీవిత భాగస్వామి"</string>
@@ -911,21 +915,21 @@
     <string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"సిమ్ కార్డు లాక్ చేయబడింది."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"సిమ్ కార్డు‌ను అన్‌లాక్ చేస్తోంది…"</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"మీరు మీ అన్‌లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విజయవంతం కాని ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్‌ను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి అడగబడతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"మీరు మీ అన్‌లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్‌ను ఉపయోగించి మీ Android TV పరికరాన్ని అన్‌లాక్ చేయాల్సిందిగా మీకు తెలపబడుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"మీరు మీ అన్‌లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విజయవంతం కాని ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్‌ను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయడానికి అడగబడతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> వైఫల్య ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్‌కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> వైఫల్య ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది, అలాగే యూజర్ డేటా మొత్తాన్ని కోల్పోతారు."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్, ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది."</string>
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"నమూనాను మర్చిపోయారా?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"ఖాతా అన్‌లాక్"</string>
-    <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేసారు"</string>
+    <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేశారు"</string>
     <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"అన్‌లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string>
     <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"వినియోగదారు పేరు (ఇమెయిల్)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"పాస్‌వర్డ్"</string>
@@ -1006,15 +1010,15 @@
     <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"మీ వెబ్ బుక్‌మార్క్‌లు మరియు చరిత్రను చదవడం"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"బ్రౌజర్ సందర్శించిన అన్ని URLల చరిత్ర గురించి మరియు అన్ని బ్రౌజర్ బుక్‌మార్క్‌ల గురించి చదవడానికి యాప్‌ను అనుమతిస్తుంది. గమనిక: ఈ అనుమతి మూడవ పక్షం బ్రౌజర్‌లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్‌ల ద్వారా అమలు చేయబడకపోవచ్చు."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"వెబ్ బుక్‌మార్క్‌లు మరియు చరిత్రను వ్రాయడం"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"మీ టాబ్లెట్‌లో నిల్వ చేయబడిన బ్రౌజర్ చరిత్రను లేదా బుక్‌మార్క్‌లను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను ఎరేజ్ చేయడానికి లేదా సవరించడానికి యాప్‌ను అనుమతించవచ్చు. గమనిక: ఈ అనుమతి మూడవ పక్షం బ్రౌజర్‌లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్‌ల ద్వారా అమలు చేయబడకపోవచ్చు."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"మీ టాబ్లెట్‌లో నిల్వ చేయబడిన బ్రౌజర్ హిస్టరీని, బుక్‌మార్క్‌లను ఎడిట్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను ఎరేజ్ చేయడానికి లేదా ఎడిట్ చేయడానికి యాప్‌ను అనుమతించవచ్చు. గమనిక: ఈ అనుమతిని థర్డ్ పార్టీ బ్రౌజర్‌లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్‌లు అమలు చేయకపోవచ్చు."</string>
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"మీ Android TV పరికరంలో నిల్వ చేసిన బ్రౌజర్ చరిత్ర లేదా బుక్‌మార్క్‌లను సవరించడానికి యాప్‌ని అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను తీసివేయడానికి లేదా సవరించడానికి యాప్‌ని అనుమతించవచ్చు. గమనిక: ఈ అనుమతి మూడవ-పక్ష బ్రౌజర్‌లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్‌ల ద్వారా అమలు కాకపోవచ్చు."</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"మీ ఫోన్‌లో నిల్వ చేయబడిన బ్రౌజర్ చరిత్రను లేదా బుక్‌మార్క్‌లను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను ఎరేజ్ చేయడానికి లేదా సవరించడానికి యాప్‌ను అనుమతించవచ్చు. గమనిక: ఈ అనుమతి మూడవ పక్షం బ్రౌజర్‌లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్‌ల ద్వారా అమలు చేయబడకపోవచ్చు."</string>
     <string name="permlab_setAlarm" msgid="1158001610254173567">"అలారం సెట్ చేయడం"</string>
     <string name="permdesc_setAlarm" msgid="2185033720060109640">"ఇన్‌స్టాల్ చేయబడిన అలారం గడియారం యాప్‌లో అలారంను సెట్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. కొన్ని అలారం గల గడియారం యాప్‌లు ఈ ఫీచర్‌ను అమలు చేయకపోవచ్చు."</string>
     <string name="permlab_addVoicemail" msgid="4770245808840814471">"వాయిస్ మెయిల్‌ను జోడించడం"</string>
-    <string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్‌బాక్స్‌కి సందేశాలను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్‌బాక్స్‌కి మెసేజ్‌లను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"బ్రౌజర్ భౌగోళిక స్థానం అనుమతులను సవరించడం"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"బ్రౌజర్ యొక్క భౌగోళిక స్థానం అనుమతులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు ఏకపక్ష వెబ్ సైట్‌లకు స్థాన సమాచారాన్ని అనుమతించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"బ్రౌజర్ యొక్క భౌగోళిక లొకేషన్ అనుమతులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు ఏకపక్ష వెబ్ సైట్‌లకు లొకేషన్ సమాచారాన్ని అనుమతించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
     <string name="save_password_message" msgid="2146409467245462965">"మీరు బ్రౌజర్ ఈ పాస్‌వర్డ్‌ను గుర్తుపెట్టుకోవాలని కోరుకుంటున్నారా?"</string>
     <string name="save_password_notnow" msgid="2878327088951240061">"ఇప్పుడు కాదు"</string>
     <string name="save_password_remember" msgid="6490888932657708341">"గుర్తుంచుకో"</string>
@@ -1039,15 +1043,15 @@
     <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>
     <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"delete"</string>
     <string name="search_go" msgid="2141477624421347086">"సెర్చ్"</string>
-    <string name="search_hint" msgid="455364685740251925">"వెతుకు..."</string>
+    <string name="search_hint" msgid="455364685740251925">"సెర్చ్ చేయండి..."</string>
     <string name="searchview_description_search" msgid="1045552007537359343">"సెర్చ్"</string>
-    <string name="searchview_description_query" msgid="7430242366971716338">"ప్రశ్నను శోధించండి"</string>
+    <string name="searchview_description_query" msgid="7430242366971716338">"ప్రశ్నను వెతకండి"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"ప్రశ్నను క్లియర్ చేయి"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"ప్రశ్నని సమర్పించండి"</string>
     <string name="searchview_description_voice" msgid="42360159504884679">"వాయిస్ శోధన"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలా?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణను ఆన్ చేసినప్పుడు, మీరు మీ వేలి క్రింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా టాబ్లెట్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
-    <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణ ఆన్ చేయబడినప్పుడు, మీరు మీ వేలి క్రింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా ఫోన్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణను ఆన్ చేసినప్పుడు, మీరు మీ వేలి కింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా టాబ్లెట్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణ ఆన్ చేయబడినప్పుడు, మీరు మీ వేలి కింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా ఫోన్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 నెల క్రితం"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"1 నెలకు ముందు"</string>
     <plurals name="last_num_days" formatted="false" msgid="687443109145393632">
@@ -1198,7 +1202,7 @@
     <string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$sతో సవరించు"</string>
     <string name="whichEditApplicationLabel" msgid="1463288652070140285">"సవరించు"</string>
     <string name="whichSendApplication" msgid="4143847974460792029">"షేర్ చేయండి"</string>
-    <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$sతో భాగస్వామ్యం చేయి"</string>
+    <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$sతో షేర్ చేయండి"</string>
     <string name="whichSendApplicationLabel" msgid="7467813004769188515">"షేర్ చేయి"</string>
     <string name="whichSendToApplication" msgid="77101541959464018">"దీన్ని ఉపయోగించి పంపండి"</string>
     <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"%1$sని ఉపయోగించి పంపండి"</string>
@@ -1209,9 +1213,9 @@
     <string name="whichImageCaptureApplication" msgid="2737413019463215284">"దీనితో చిత్రాన్ని క్యాప్చర్ చేయి"</string>
     <string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"%1$sతో చిత్రాన్ని క్యాప్చర్ చేయండి"</string>
     <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
-    <string name="alwaysUse" msgid="3153558199076112903">"ఈ చర్యకు డిఫాల్ట్‌గా ఉపయోగించండి."</string>
+    <string name="alwaysUse" msgid="3153558199076112903">"ఈ చర్యకు ఆటోమేటిక్‌గా ఉపయోగించండి."</string>
     <string name="use_a_different_app" msgid="4987790276170972776">"వేరొక యాప్‌ను ఉపయోగించండి"</string>
-    <string name="clearDefaultHintMsg" msgid="1325866337702524936">"సిస్టమ్ సెట్టింగ్‌లు &gt; యాప్‌లు &gt; డౌన్‌లోడ్ చేయబడినవిలో డిఫాల్ట్‌ను క్లియర్ చేయి."</string>
+    <string name="clearDefaultHintMsg" msgid="1325866337702524936">"సిస్టమ్ సెట్టింగ్‌లు &gt; యాప్‌లు &gt; డౌన్‌లోడ్ చేయబడినవిలో ఆటోమేటిక్‌ను క్లియర్ చేయి."</string>
     <string name="chooseActivity" msgid="8563390197659779956">"చర్యను ఎంచుకోండి"</string>
     <string name="chooseUsbActivity" msgid="2096269989990986612">"USB పరికరం కోసం యాప్‌ను ఎంచుకోండి"</string>
     <string name="noApplications" msgid="1186909265235544019">"ఈ చర్యను అమలు చేయగల యాప్‌లు ఏవీ లేవు."</string>
@@ -1259,7 +1263,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>
@@ -1275,7 +1279,7 @@
     <string name="dump_heap_notification" msgid="5316644945404825032">"<xliff:g id="PROC">%1$s</xliff:g> మెమరీ పరిమితిని మించిపోయింది"</string>
     <string name="dump_heap_ready_notification" msgid="2302452262927390268">"<xliff:g id="PROC">%1$s</xliff:g> హీప్ డంప్ సిద్ధంగా ఉంది"</string>
     <string name="dump_heap_notification_detail" msgid="8431586843001054050">"కుప్పలు తెప్పలుగా సేకరించబడింది. షేర్ చేయడానికి నొక్కండి"</string>
-    <string name="dump_heap_title" msgid="4367128917229233901">"హీప్ డంప్‌ను భాగస్వామ్యం చేయాలా?"</string>
+    <string name="dump_heap_title" msgid="4367128917229233901">"హీప్ డంప్‌ను షేర్ చేయాలా?"</string>
     <string name="dump_heap_text" msgid="1692649033835719336">"ఈ <xliff:g id="PROC">%1$s</xliff:g> ప్రాసెస్ దీని మెమరీ పరిమితి అయిన <xliff:g id="SIZE">%2$s</xliff:g>ని మించిపోయింది. మీరు దీని డెవలపర్‌తో షేర్ చేయడానికి హీప్ డంప్ అందుబాటులో ఉంది. జాగ్రత్త: ఈ హీప్ డంప్‌లో అప్లికేషన్ యాక్సెస్ కలిగి ఉన్న మీ వ్యక్తిగత సమాచారం ఏదైనా ఉండవచ్చు."</string>
     <string name="dump_heap_system_text" msgid="6805155514925350849">"ఈ <xliff:g id="PROC">%1$s</xliff:g> ప్రాసెస్ దాని మెమరీ పరిమితి <xliff:g id="SIZE">%2$s</xliff:g>ని మించిపోయింది. మీరు షేర్ చేయడానికి హీప్ డంప్ అందుబాటులో ఉంది. జాగ్రత్త: ఈ హీప్ డంప్ ప్రాసెస్ విధానంలో గోప్యమైన వ్యక్తిగత సమాచారం యాక్సెస్ చేసే అవకాశం ఉంది, వీటిలో మీరు టైప్ చేసే అంశాలు కూడా ఉండవచ్చు."</string>
     <string name="dump_heap_ready_text" msgid="5849618132123045516">"మీరు షేర్ చేయదలుచుకున్న <xliff:g id="PROC">%1$s</xliff:g> యొక్క హీప్ డంప్ ప్రాసెస్ విధానం అందుబాటులో ఉంది. జాగ్రత్త: ఈ హీప్ డంప్ ప్రాసెస్ విధానంలో గోప్యమైన వ్యక్తిగత సమాచారం యాక్సెస్ చేసే అవకాశం ఉంది, వీటిలో మీరు టైప్ చేసే అంశాలు కూడా ఉండవచ్చు."</string>
@@ -1294,7 +1298,7 @@
     <string name="volume_icon_description_incall" msgid="4491255105381227919">"కాల్ వాల్యూమ్"</string>
     <string name="volume_icon_description_media" msgid="4997633254078171233">"మీడియా వాల్యూమ్"</string>
     <string name="volume_icon_description_notification" msgid="579091344110747279">"నోటిఫికేషన్ వాల్యూమ్"</string>
-    <string name="ringtone_default" msgid="9118299121288174597">"డిఫాల్ట్ రింగ్‌టోన్"</string>
+    <string name="ringtone_default" msgid="9118299121288174597">"ఆటోమేటిక్ రింగ్‌టోన్"</string>
     <string name="ringtone_default_with_actual" msgid="2709686194556159773">"ఆటోమేటిక్ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="397111123930141876">"ఏదీ వద్దు"</string>
     <string name="ringtone_picker_title" msgid="667342618626068253">"రింగ్‌టోన్‌లు"</string>
@@ -1326,11 +1330,11 @@
     <string name="accept" msgid="5447154347815825107">"ఆమోదిస్తున్నాను"</string>
     <string name="decline" msgid="6490507610282145874">"తిరస్కరిస్తున్నాను"</string>
     <string name="select_character" msgid="3352797107930786979">"అక్షరాన్ని చొప్పించండి"</string>
-    <string name="sms_control_title" msgid="4748684259903148341">"SMS సందేశాలు పంపుతోంది"</string>
-    <string name="sms_control_message" msgid="6574313876316388239">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; పెద్ద సంఖ్యలో SMS సందేశాలను పంపుతోంది. సందేశాలను పంపడం కొనసాగించడానికి మీరు ఈ యాప్‌ను అనుమతించాలనుకుంటున్నారా?"</string>
+    <string name="sms_control_title" msgid="4748684259903148341">"SMS మెసేజ్‌లు పంపుతోంది"</string>
+    <string name="sms_control_message" msgid="6574313876316388239">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; పెద్ద సంఖ్యలో SMS మెసేజ్‌లను పంపుతోంది. మెసేజ్‌లను పంపడం కొనసాగించడానికి మీరు ఈ యాప్‌ను అనుమతించాలనుకుంటున్నారా?"</string>
     <string name="sms_control_yes" msgid="4858845109269524622">"అనుమతిస్తున్నాను"</string>
     <string name="sms_control_no" msgid="4845717880040355570">"తిరస్కరిస్తున్నాను"</string>
-    <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ఒక సందేశాన్ని &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;కి పంపాలనుకుంటోంది."</string>
+    <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ఒక మెసేజ్‌ను &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;కి పంపాలనుకుంటోంది."</string>
     <string name="sms_short_code_details" msgid="2723725738333388351">"దీని వలన మీ మొబైల్ ఖాతాకు "<b>"ఛార్జీలు విధించబడవచ్చు"</b>"."</string>
     <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"దీని వలన మీ మొబైల్ ఖాతాకు ఛార్జీలు విధించబడవచ్చు."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"పంపు"</string>
@@ -1385,10 +1389,10 @@
     <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"USB పోర్ట్ ఆటోమేటిక్‌గా నిలిపివేయబడింది. మరింత తెలుసుకోవడానికి నొక్కండి."</string>
     <string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"USB పోర్ట్‌ను ఉపయోగించడం సురక్షితం"</string>
     <string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"ఫోన్ ఇకపై ద్రవ లేదా వ్యర్థ పదార్థాలను గుర్తించదు."</string>
-    <string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"బగ్ నివేదికను తీస్తోంది…"</string>
-    <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
-    <string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
-    <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. యాప్‌లు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"బగ్ రిపోర్ట్‌ను తీస్తోంది…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ రిపోర్ట్‌ను షేర్ చేయాలా?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ రిపోర్ట్‌ను షేర్ చేస్తోంది..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ అడ్మిన్ ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ రిపోర్ట్‌ను రిక్వెస్ట్ చేశారు. యాప్‌లు మరియు డేటా షేర్ చేయబడవచ్చు."</string>
     <string name="share_remote_bugreport_action" msgid="7630880678785123682">"షేర్ చేయి"</string>
     <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"తిరస్కరిస్తున్నాను"</string>
     <string name="select_input_method" msgid="3971267998568587025">"ఇన్‌పుట్ పద్ధతిని ఎంచుకోండి"</string>
@@ -1420,7 +1424,7 @@
     <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"మీరు పరికరాన్ని తిరిగి ఫార్మాట్ చేయాల్సి ఉంటుంది. తొలగించడానికి ట్యాప్ చేయండి"</string>
     <string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"<xliff:g id="NAME">%s</xliff:g>కి మద్దతు లేదు"</string>
     <string name="ext_media_unsupported_notification_title" product="automotive" msgid="6004193172658722381">"<xliff:g id="NAME">%s</xliff:g> పని చేయటం లేదు"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"ఈ పరికరం ఈ <xliff:g id="NAME">%s</xliff:g>కి మద్దతు ఇవ్వదు. మద్దతు కలిగిన ఆకృతిలో సెటప్ చేయడానికి నొక్కండి."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"ఈ పరికరం ఈ <xliff:g id="NAME">%s</xliff:g>‌కు సపోర్ట్‌ ఇవ్వదు. సపోర్ట్‌ ఉన్న ఫార్మాట్‌లో సెటప్ చేయడానికి నొక్కండి."</string>
     <string name="ext_media_unsupported_notification_message" product="tv" msgid="1595482802187036532">"సపోర్ట్ చేసే ఫార్మాట్‌లో <xliff:g id="NAME">%s</xliff:g>ను సెటప్ చేయడానికి ఎంచుకోండి."</string>
     <string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"మీరు పరికరాన్ని తిరిగి ఫార్మాట్ చేయాల్సి ఉంటుంది"</string>
     <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> ఊహించని విధంగా తీసివేయబడింది"</string>
@@ -1475,10 +1479,10 @@
     <string name="ime_action_previous" msgid="6548799326860401611">"మునుపటి"</string>
     <string name="ime_action_default" msgid="8265027027659800121">"అమలు చేయి"</string>
     <string name="dial_number_using" msgid="6060769078933953531">"<xliff:g id="NUMBER">%s</xliff:g>ని ఉపయోగించి\nనంబర్ డయల్ చేయండి"</string>
-    <string name="create_contact_using" msgid="6200708808003692594">"<xliff:g id="NUMBER">%s</xliff:g>ని ఉపయోగించి\nపరిచయాన్ని సృష్టించండి"</string>
-    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"క్రింది ఒకటి లేదా అంతకంటే ఎక్కువ యాప్‌లు మీ ఖాతాను యాక్సెస్ చేయడానికి ఇప్పుడు మరియు భవిష్యత్తులో అనుమతిని అభ్యర్థించవచ్చు."</string>
-    <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"మీరు ఈ అభ్యర్థనను అనుమతించాలనుకుంటున్నారా?"</string>
-    <string name="grant_permissions_header_text" msgid="3420736827804657201">"యాక్సెస్ అభ్యర్థన"</string>
+    <string name="create_contact_using" msgid="6200708808003692594">"<xliff:g id="NUMBER">%s</xliff:g>ని ఉపయోగించి\nకాంటాక్ట్‌ను క్రియేట్ చేయండి"</string>
+    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"కింది ఒకటి లేదా అంతకంటే ఎక్కువ యాప్‌లు మీ ఖాతాను యాక్సెస్ చేయడానికి ఇప్పుడు మరియు భవిష్యత్తులో అనుమతిని అభ్యర్థించవచ్చు."</string>
+    <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"మీరు ఈ రిక్వెస్ట్‌ను అనుమతించాలనుకుంటున్నారా?"</string>
+    <string name="grant_permissions_header_text" msgid="3420736827804657201">"యాక్సెస్ రిక్వెస్ట్‌"</string>
     <string name="allow" msgid="6195617008611933762">"అనుమతించండి"</string>
     <string name="deny" msgid="6632259981847676572">"తిరస్కరించండి"</string>
     <string name="permission_request_notification_title" msgid="1810025922441048273">"అనుమతి అభ్యర్థించబడింది"</string>
@@ -1487,7 +1491,7 @@
     <string name="forward_intent_to_owner" msgid="4620359037192871015">"మీరు మీ కార్యాలయ ప్రొఫైల్‌కు వెలుపల ఈ యాప్‌ను ఉపయోగిస్తున్నారు"</string>
     <string name="forward_intent_to_work" msgid="3620262405636021151">"మీరు మీ కార్యాలయ ప్రొఫైల్‌లో ఈ యాప్‌ను ఉపయోగిస్తున్నారు"</string>
     <string name="input_method_binding_label" msgid="1166731601721983656">"ఇన్‌పుట్ పద్ధతి"</string>
-    <string name="sync_binding_label" msgid="469249309424662147">"సమకాలీకరణ"</string>
+    <string name="sync_binding_label" msgid="469249309424662147">"సింక్‌"</string>
     <string name="accessibility_binding_label" msgid="1974602776545801715">"యాక్సెసిబిలిటీ"</string>
     <string name="wallpaper_binding_label" msgid="1197440498000786738">"వాల్‌పేపర్"</string>
     <string name="chooser_wallpaper" msgid="3082405680079923708">"వాల్‌పేపర్‌ను మార్చండి"</string>
@@ -1526,8 +1530,8 @@
     <string name="websearch" msgid="5624340204512793290">"వెబ్ శోధన"</string>
     <string name="find_next" msgid="5341217051549648153">"తదుపరిదాన్ని కనుగొను"</string>
     <string name="find_previous" msgid="4405898398141275532">"మునుపటిదాన్ని కనుగొను"</string>
-    <string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g> నుండి స్థాన అభ్యర్థన"</string>
-    <string name="gpsNotifTitle" msgid="1590033371665669570">"స్థాన అభ్యర్థన"</string>
+    <string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g> నుండి లొకేషన్ రిక్వెస్ట్‌"</string>
+    <string name="gpsNotifTitle" msgid="1590033371665669570">"లొకేషన్ రిక్వెస్ట్‌"</string>
     <string name="gpsNotifMessage" msgid="7346649122793758032">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>) ద్వారా అభ్యర్థించబడింది"</string>
     <string name="gpsVerifYes" msgid="3719843080744112940">"అవును"</string>
     <string name="gpsVerifNo" msgid="1671201856091564741">"కాదు"</string>
@@ -1665,7 +1669,7 @@
     <string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK కోడ్ 8 సంఖ్యలు ఉండాలి."</string>
     <string name="kg_invalid_puk" msgid="4809502818518963344">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. పునరావృత ప్రయత్నాల వలన సిమ్ శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"పిన్‌ కోడ్‌లు సరిపోలలేదు"</string>
-    <string name="kg_login_too_many_attempts" msgid="699292728290654121">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేసారు"</string>
+    <string name="kg_login_too_many_attempts" msgid="699292728290654121">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేశారు"</string>
     <string name="kg_login_instructions" msgid="3619844310339066827">"అన్‌లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string>
     <string name="kg_login_username_hint" msgid="1765453775467133251">"వినియోగదారు పేరు (ఇమెయిల్)"</string>
     <string name="kg_login_password_hint" msgid="3330530727273164402">"పాస్‌వర్డ్"</string>
@@ -1673,15 +1677,15 @@
     <string name="kg_login_invalid_input" msgid="8292367491901220210">"చెల్లని వినియోగదారు పేరు లేదా పాస్‌వర్డ్."</string>
     <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"మీ వినియోగదారు పేరు లేదా పాస్‌వర్డ్‌ను మర్చిపోయారా?\n"<b>"google.com/accounts/recovery"</b>"ని సందర్శించండి."</string>
     <string name="kg_login_checking_password" msgid="4676010303243317253">"ఖాతాను తనిఖీ చేస్తోంది…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్‌కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది, అలాగే యూజర్, డేటా మొత్తాన్ని కోల్పోతారు."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్‌కు రీసెట్ చేయబడుతుంది."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత మీ Android TV పరికరాన్ని ఇమెయిల్ ఖాతా ద్వారా అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని కోరడం జరుగుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"షార్ట్‌కట్ ఆన్ చేసి ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్‌లను 3 సెకన్ల పాటు నొక్కి ఉంచితే యాక్సెస్ సౌలభ్య ఫీచర్ ప్రారంభం అవుతుంది."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"యాక్సెస్ సౌలభ్య ఫీచర్‌ల కోసం షార్ట్‌కట్‌ను ఆన్ చేయాలా?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"రెండు వాల్యూమ్ కీలను కొంత సేపు నొక్కి పట్టుకుంటే యాక్సెసిబిలిటీ ఫీచ‌ర్‌లు ఆన్ అవుతాయి. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nప్రస్తుత ఫీచర్లు:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nఎంపిక చేసిన ఫీచర్లను మీరు సెట్టింగ్‌లు&gt;యాక్సెసిబిలిటీలో మార్చవచ్చు."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> షార్ట్‌కట్‌ను ఆన్ చేయాలా?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"రెండు వాల్యూమ్ కీలను కొన్ని సెకన్ల పాటు నొక్కి పట్టుకోవడం ద్వారా యాక్సెసిబిలిటీ అయిన <xliff:g id="SERVICE">%1$s</xliff:g> ఆన్ అవుతుంది. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nసెట్టింగ్‌లు &gt; యాక్సెసిబిలిటీలో, వేరొక ఫీచర్‌ను ప్రారంభించేలా ఈ షార్ట్ కట్‌ను మీరు మార్చవచ్చు."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ఆన్ చేయి"</string>
@@ -1714,8 +1719,8 @@
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ఆఫ్ చేయబడింది"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"షార్ట్‌కట్‌లను ఎడిట్ చేయి"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"పూర్తయింది"</string>
-    <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string>
-    <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"సత్వరమార్గాన్ని ఉపయోగించు"</string>
+    <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"షార్ట్‌కట్‌ను ఆఫ్ చేయి"</string>
+    <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"షార్ట్‌కట్‌ను ఉపయోగించు"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"కలర్ మార్పిడి"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"కలర్ సరిచేయడం"</string>
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"వన్-హ్యాండెడ్ మోడ్"</string>
@@ -1870,7 +1875,7 @@
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ ఆకృతి కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
-    <string name="package_installed_device_owner" msgid="7035926868974878525">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేసారు"</string>
+    <string name="package_installed_device_owner" msgid="7035926868974878525">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేశారు"</string>
     <string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
@@ -1927,14 +1932,14 @@
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> కొన్ని ధ్వనులను మ్యూట్ చేస్తోంది"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"మీ పరికరంతో అంతర్గత సమస్య ఏర్పడింది మరియు మీరు ఫ్యాక్టరీ డేటా రీసెట్ చేసే వరకు అస్థిరంగా ఉంటుంది."</string>
     <string name="system_error_manufacturer" msgid="703545241070116315">"మీ పరికరంతో అంతర్గత సమస్య ఏర్పడింది. వివరాల కోసం మీ తయారీదారుని సంప్రదించండి."</string>
-    <string name="stk_cc_ussd_to_dial" msgid="3139884150741157610">"USSD అభ్యర్థన సాధారణ కాల్‌కు మార్చబడింది"</string>
-    <string name="stk_cc_ussd_to_ss" msgid="4826846653052609738">"USSD అభ్యర్థన SS అభ్యర్థనకు మార్చబడింది"</string>
-    <string name="stk_cc_ussd_to_ussd" msgid="8343001461299302472">"కొత్త USSD అభ్యర్థనకు మార్చబడింది"</string>
-    <string name="stk_cc_ussd_to_dial_video" msgid="429118590323618623">"USSD అభ్యర్థన వీడియో కాల్‌కు మార్చబడింది"</string>
-    <string name="stk_cc_ss_to_dial" msgid="4087396658768717077">"SS అభ్యర్థన సాధారణ కాల్‌కి మార్చబడింది"</string>
-    <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS అభ్యర్థన వీడియో కాల్‌కి మార్చబడింది"</string>
-    <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS అభ్యర్థన USSD అభ్యర్థనకు మార్చబడింది"</string>
-    <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"కొత్త SS అభ్యర్థనకు మార్చబడింది"</string>
+    <string name="stk_cc_ussd_to_dial" msgid="3139884150741157610">"USSD రిక్వెస్ట్‌ సాధారణ కాల్‌కు మార్చబడింది"</string>
+    <string name="stk_cc_ussd_to_ss" msgid="4826846653052609738">"USSD రిక్వెస్ట్‌ SS రిక్వెస్ట్‌కు మార్చబడింది"</string>
+    <string name="stk_cc_ussd_to_ussd" msgid="8343001461299302472">"కొత్త USSD రిక్వెస్ట్‌కు మార్చబడింది"</string>
+    <string name="stk_cc_ussd_to_dial_video" msgid="429118590323618623">"USSD రిక్వెస్ట్‌ వీడియో కాల్‌కు మార్చబడింది"</string>
+    <string name="stk_cc_ss_to_dial" msgid="4087396658768717077">"SS రిక్వెస్ట్‌ సాధారణ కాల్‌కి మార్చబడింది"</string>
+    <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS రిక్వెస్ట్‌ వీడియో కాల్‌కి మార్చబడింది"</string>
+    <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS రిక్వెస్ట్‌ USSD రిక్వెస్ట్‌కు మార్చబడింది"</string>
+    <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"కొత్త SS రిక్వెస్ట్‌కు మార్చబడింది"</string>
     <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ఫిషింగ్ అలర్ట్"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ఆఫీస్ ప్రొఫైల్‌"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"హెచ్చరించబడింది"</string>
@@ -1962,7 +1967,7 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
     </plurals>
     <string name="default_notification_channel_label" msgid="3697928973567217330">"వర్గీకరించబడలేదు"</string>
-    <string name="importance_from_user" msgid="2782756722448800447">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
+    <string name="importance_from_user" msgid="2782756722448800447">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేశారు."</string>
     <string name="importance_from_person" msgid="4235804979664465383">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
     <string name="notification_history_title_placeholder" msgid="7748630986182249599">"అనుకూల యాప్ నోటిఫికేషన్"</string>
     <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) ?"</string>
@@ -1985,13 +1990,13 @@
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ఈ యాప్ పాత వెర్షన్ Android కోసం రూపొందించబడింది మరియు అది సరిగ్గా పని చేయకపోవచ్చు. అప్‌డేట్‌ల కోసం తనిఖీ చేయడానికి ప్రయత్నించండి లేదా డెవలపర్‌ని సంప్రదించండి."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"అప్‌డేట్ కోసం తనిఖీ చేయండి"</string>
-    <string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string>
+    <string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త మెసేజ్‌లు ఉన్నాయి"</string>
     <string name="new_sms_notification_content" msgid="3197949934153460639">"వీక్షించడానికి SMS యాప్‌ను తెరవండి"</string>
     <string name="profile_encrypted_title" msgid="9001208667521266472">"కొంత ఫంక్షనాలిటీ పరిమితం కావచ్చు"</string>
     <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>
@@ -2042,20 +2047,20 @@
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ఇప్పుడు కాదు"</string>
     <string name="autofill_save_never" msgid="6821841919831402526">"ఎప్పుడూ వద్దు"</string>
     <string name="autofill_update_yes" msgid="4608662968996874445">"అప్‌డేట్ చేయి"</string>
-    <string name="autofill_continue_yes" msgid="7914985605534510385">"కొనసాగించు"</string>
+    <string name="autofill_continue_yes" msgid="7914985605534510385">"కొనసాగించండి"</string>
     <string name="autofill_save_type_password" msgid="5624528786144539944">"పాస్‌వర్డ్"</string>
-    <string name="autofill_save_type_address" msgid="3111006395818252885">"చిరునామా"</string>
+    <string name="autofill_save_type_address" msgid="3111006395818252885">"అడ్రస్‌"</string>
     <string name="autofill_save_type_credit_card" msgid="3583795235862046693">"క్రెడిట్ కార్డ్"</string>
     <string name="autofill_save_type_debit_card" msgid="3169397504133097468">"డెబిట్ కార్డ్"</string>
     <string name="autofill_save_type_payment_card" msgid="6555012156728690856">"చెల్లింపు కార్డ్"</string>
     <string name="autofill_save_type_generic_card" msgid="1019367283921448608">"కార్డ్"</string>
     <string name="autofill_save_type_username" msgid="1018816929884640882">"వినియోగదారు పేరు"</string>
-    <string name="autofill_save_type_email_address" msgid="1303262336895591924">"ఇమెయిల్ చిరునామా"</string>
+    <string name="autofill_save_type_email_address" msgid="1303262336895591924">"ఇమెయిల్ అడ్రస్‌"</string>
     <string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string>
     <string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"వెంటనే తీర ప్రాంతాలు మరియు నదీ పరీవాహక ప్రాంతాలను ఖాళీ చేసి మెట్ట ప్రాంతాలకు తరలి వెళ్లండి."</string>
     <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string>
-    <string name="etws_primary_default_message_test" msgid="4583367373909549421">"అత్యవసర సందేశాల పరీక్ష"</string>
-    <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"ప్రత్యుత్తరం పంపండి"</string>
+    <string name="etws_primary_default_message_test" msgid="4583367373909549421">"అత్యవసర మెసేజ్‌ల పరీక్ష"</string>
+    <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"రిప్లయి పంపండి"</string>
     <string name="etws_primary_default_message_others" msgid="7958161706019130739"></string>
     <string name="mmcc_authentication_reject" msgid="4891965994643876369">"వాయిస్ కోసం SIM అనుమతించబడదు"</string>
     <string name="mmcc_imsi_unknown_in_hlr" msgid="227760698553988751">"వాయిస్ కోసం SIM సదుపాయం లేదు"</string>
@@ -2067,18 +2072,18 @@
     <string name="mmcc_illegal_me_msim_template" msgid="4802735138861422802">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> అనుమతించబడదు"</string>
     <string name="popup_window_default_title" msgid="6907717596694826919">"పాప్అప్ విండో"</string>
     <string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
-    <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"యాప్ వెర్షన్ డౌన్‌గ్రేడ్ చేయబడింది లేదా ఈ సత్వరమార్గంతో అనుకూలంగా లేదు"</string>
-    <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"బ్యాకప్ మరియు పునరుద్ధరణకు యాప్ మద్దతు ఇవ్వని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
-    <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"యాప్ సంతకం సరిపోలని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
-    <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"యాప్ వెర్షన్ డౌన్‌గ్రేడ్ చేయబడింది లేదా ఈ షార్ట్‌కట్‌తో అనుకూలంగా లేదు"</string>
+    <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"బ్యాకప్ మరియు పునరుద్ధరణకు యాప్ మద్దతు ఇవ్వని కారణంగా షార్ట్‌కట్‌ను పునరుద్ధరించడం సాధ్యపడలేదు"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"యాప్ సంతకం సరిపోలని కారణంగా షార్ట్‌కట్‌ను పునరుద్ధరించడం సాధ్యపడలేదు"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"షార్ట్‌కట్‌ను పునరుద్ధరించడం సాధ్యపడలేదు"</string>
     <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"షార్ట్‌కట్ నిలిపివేయబడింది"</string>
     <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"అన్ఇన్‌స్టాల్ చేయండి"</string>
     <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ఏదేమైనా తెరువు"</string>
     <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 +2105,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,17 +2135,17 @@
     <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>
-    <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"యాప్‌ల జాబితా"</string>
+    <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"యాప్‌ల లిస్ట్‌"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ఈ యాప్‌కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
     <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"హోమ్"</string>
     <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"వెనుకకు"</string>
     <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"ఇటీవలి యాప్‌లు"</string>
     <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"నోటిఫికేషన్‌లు"</string>
-    <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"శీఘ్ర సెట్టింగ్‌లు"</string>
+    <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"క్విక్ సెట్టింగ్‌లు"</string>
     <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"పవర్ డైలాగ్‌ను తెరువు"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్‌ను లాక్ చేయి"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్‌షాట్"</string>
@@ -2226,17 +2231,17 @@
     <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_IN_PROGRESS" msgid="2695664012344346788">"PUK అన్‌లాక్‌ను అభ్యర్థిస్తోంది…"</string>
     <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_IN_PROGRESS" msgid="2695678959963807782">"PUK అన్‌లాక్‌ను అభ్యర్థిస్తోంది…"</string>
     <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_IN_PROGRESS" msgid="1230605365926493599">"PUK అన్‌లాక్‌ను అభ్యర్థిస్తోంది…"</string>
-    <string name="PERSOSUBSTATE_SIM_NETWORK_ERROR" msgid="1924844017037151535">"SIM నెట్‌వర్క్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ERROR" msgid="3372797822292089708">"SIM నెట్‌వర్క్ సబ్‌సెట్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ERROR" msgid="1878443146720411381">"SIM సర్వీస్ ప్రొవైడర్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_CORPORATE_ERROR" msgid="7664778312218023192">"SIM కార్పొరేట్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_SIM_ERROR" msgid="2472944311643350302">"SIM అన్‌లాక్‌ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_NETWORK1_ERROR" msgid="828089694480999120">"RUIM నెట్‌వర్క్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_NETWORK2_ERROR" msgid="17619001007092511">"RUIM నెట్‌వర్క్2 అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_HRPD_ERROR" msgid="807214229604353614">"RUIM Hrpd అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_CORPORATE_ERROR" msgid="8644184447744175747">"RUIM కార్పొరేట్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR" msgid="3801002648649640407">"RUIM సర్వీస్ ప్రొవైడర్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_RUIM_ERROR" msgid="707397021218680753">"RUIM అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_NETWORK_ERROR" msgid="1924844017037151535">"SIM నెట్‌వర్క్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ERROR" msgid="3372797822292089708">"SIM నెట్‌వర్క్ సబ్‌సెట్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ERROR" msgid="1878443146720411381">"SIM సర్వీస్ ప్రొవైడర్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_CORPORATE_ERROR" msgid="7664778312218023192">"SIM కార్పొరేట్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_SIM_ERROR" msgid="2472944311643350302">"SIM అన్‌లాక్‌ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_NETWORK1_ERROR" msgid="828089694480999120">"RUIM నెట్‌వర్క్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_NETWORK2_ERROR" msgid="17619001007092511">"RUIM నెట్‌వర్క్2 అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_HRPD_ERROR" msgid="807214229604353614">"RUIM Hrpd అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_CORPORATE_ERROR" msgid="8644184447744175747">"RUIM కార్పొరేట్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR" msgid="3801002648649640407">"RUIM సర్వీస్ ప్రొవైడర్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_RUIM_ERROR" msgid="707397021218680753">"RUIM అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUK అన్‌లాక్ విజయవంతం కాలేదు."</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUK అన్‌లాక్ విజయవంతం కాలేదు."</string>
     <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUK అన్‌లాక్ విజయవంతం కాలేదు."</string>
@@ -2248,11 +2253,11 @@
     <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUK అన్‌లాక్ విజయవంతం కాలేదు."</string>
     <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUK అన్‌లాక్ విజయవంతం కాలేదు."</string>
     <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUK అన్‌లాక్ విజయవంతం కాలేదు."</string>
-    <string name="PERSOSUBSTATE_SIM_SPN_ERROR" msgid="9017576601595353649">"SPN అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR" msgid="1116993930995545742">"SP Equivalent Home PLMN అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_ICCID_ERROR" msgid="7559167306794441462">"ICCID అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_IMPI_ERROR" msgid="2782926139511136588">"IMPI నెట్‌వర్క్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
-    <string name="PERSOSUBSTATE_SIM_NS_SP_ERROR" msgid="1890493954453456758">"నెట్‌వర్క్ సబ్‌సెట్ సర్వీస్ ప్రొవైడర్ అన్‌లాక్ అభ్యర్థన విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_SPN_ERROR" msgid="9017576601595353649">"SPN అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR" msgid="1116993930995545742">"SP Equivalent Home PLMN అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_ICCID_ERROR" msgid="7559167306794441462">"ICCID అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_IMPI_ERROR" msgid="2782926139511136588">"IMPI నెట్‌వర్క్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
+    <string name="PERSOSUBSTATE_SIM_NS_SP_ERROR" msgid="1890493954453456758">"నెట్‌వర్క్ సబ్‌సెట్ సర్వీస్ ప్రొవైడర్ అన్‌లాక్ రిక్వెస్ట్‌ విఫలమైంది."</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_SUCCESS" msgid="4886243367747126325">"SIM నెట్‌వర్క్ అన్‌లాక్ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_SUCCESS" msgid="4053809277733513987">"SIM నెట్‌వర్క్ సబ్‌సెట్ అన్‌లాక్ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_SUCCESS" msgid="8249342930499801740">"SIM సర్వీస్ ప్రొవైడర్ అన్‌లాక్ విజయవంతమైంది."</string>
@@ -2260,9 +2265,9 @@
     <string name="PERSOSUBSTATE_SIM_SIM_SUCCESS" msgid="6975608174152828954">"SIM అన్‌లాక్‌ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_RUIM_NETWORK1_SUCCESS" msgid="2846699261330463192">"RUIM నెట్‌వర్క్1 అన్‌లాక్ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_RUIM_NETWORK2_SUCCESS" msgid="5335414726057102801">"RUIM నెట్‌వర్క్2 అన్‌లాక్ విజయవంతమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_HRPD_SUCCESS" msgid="8868100318474971969">"RUIM Hrpd అన్‌లాక్ అభ్యర్థన విజయవంతమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_HRPD_SUCCESS" msgid="8868100318474971969">"RUIM Hrpd అన్‌లాక్ రిక్వెస్ట్‌ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS" msgid="6020936629725666932">"RUIM సర్వీస్ ప్రొవైడర్ అన్‌లాక్ విజయవంతమైంది."</string>
-    <string name="PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS" msgid="6944873647584595489">"RUIM కార్పొరేట్ అన్‌లాక్ అభ్యర్థన విజయవంతమైంది."</string>
+    <string name="PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS" msgid="6944873647584595489">"RUIM కార్పొరేట్ అన్‌లాక్ రిక్వెస్ట్‌ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_RUIM_RUIM_SUCCESS" msgid="2526483514124121988">"RUIM అన్‌లాక్ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUK అన్‌లాక్ విజయవంతమైంది."</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUK అన్‌లాక్ విజయవంతమైంది."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 44516d7..7452ad1 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"การปลดล็อกด้วยใบหน้า"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"มีปัญหาเกี่ยวกับฟีเจอร์ปลดล็อกด้วยใบหน้า"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ใช้ใบหน้าหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"ไอคอนใบหน้า"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"อ่านการตั้งค่าการซิงค์"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"อนุญาตให้แอปพลิเคชันอ่านการตั้งค่าการซิงค์ของบัญชี ตัวอย่างเช่น การอนุญาตนี้สามารถระบุได้ว่าแอปพลิเคชัน People ซิงค์กับบัญชีหรือไม่"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มนาน 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"เปิดใช้ทางลัดสำหรับฟีเจอร์การช่วยเหลือพิเศษใช่ไหม"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 2-3 วินาทีจะเปิดฟีเจอร์การช่วยเหลือพิเศษ การดำเนินการนี้อาจเปลี่ยนแปลงลักษณะการทำงานของอุปกรณ์\n\nฟีเจอร์ปัจจุบัน:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nคุณจะเปลี่ยนฟีเจอร์ที่เลือกไว้ได้ในการตั้งค่า &gt; การช่วยเหลือพิเศษ"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"เปิดใช้ทางลัด <xliff:g id="SERVICE">%1$s</xliff:g> ใช่ไหม"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 2-3 วินาทีจะเปิด <xliff:g id="SERVICE">%1$s</xliff:g> ซึ่งเป็นฟีเจอร์การช่วยเหลือพิเศษ การดำเนินการนี้อาจเปลี่ยนแปลงลักษณะการทำงานของอุปกรณ์\n\nคุณแก้ไขทางลัดนี้ให้เปิดฟีเจอร์อื่นได้ในการตั้งค่า &gt; การช่วยเหลือพิเศษ"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"เปิด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a21c4f0..78fcafb 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gamitin ang iyong fingerprint o lock ng screen para magpatuloy"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icon ng fingerprint"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Pag-unlock Gamit ang Mukha"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Isyu sa Pag-unlock Gamit ang Mukha"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gamitin ang iyong mukha o lock ng screen para magpatuloy"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"basahin ang mga setting ng sync"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Pinapayagan ang app na basahin ang mga setting ng pag-sync para sa isang account. Halimbawa, matutukoy nito kung naka-sync ang app na Mga Tao sa isang account."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"I-on ang shortcut para sa mga feature ng pagiging naa-access?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mao-on ang mga feature ng accessibility kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nMga kasalukuyang feature:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuwede mong baguhin ang mga napiling feature sa Mga Setting &gt; Accessibility."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"I-on ang shortcut ng <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mao-on ang feature ng accessibility na <xliff:g id="SERVICE">%1$s</xliff:g> kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nPuwede mong palitan ng ibang feature ang shortcut na ito sa Mga Setting &gt; Accessibility."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"I-on"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index deda317..92aeea1 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Devam etmek için parmak izi veya ekran kilidinizi kullanın"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Parmak izi simgesi"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Yüz Tanıma Kilidi"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Yüz Tanıma Kilidi sorunu"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Devam etmek için yüz veya ekran kilidinizi kullanın"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Yüz simgesi"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"senk. ayarlarını okuma"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Uygulamaya bir hesaba ait senkronizasyon ayarlarını okuma izni verir. Örneğin, bu izne sahip bir uygulama Kişiler uygulamasının bir hesapla senkronize olup olmadığını belirleyebilir."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kısayol açıkken ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erişilebilirlik özellikleri için kısayol açılsın mı?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ses tuşlarının ikisini birden birkaç saniyeliğine basılı tutmak, erişilebilirlik özelliklerini açar. Bu, cihazınızın çalışma şeklini değiştirebilir.\n\nGeçerli özellikler:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nSeçilen özellikleri Ayarlar &gt; Erişilebilirlik\'te değiştirebilirsiniz."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> kısayolu açılsın mı?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ses tuşlarının ikisini birden birkaç saniyeliğine basılı tutmak <xliff:g id="SERVICE">%1$s</xliff:g> erişilebilirlik özelliğini etkinleştirir. Bu, cihazınızın çalışma şeklini değiştirebilir.\n\nBu kısayolu, Ayarlar &gt; Erişilebilirlik\'te başka bir özellikle değiştirebilirsiniz."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Etkinleştir"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index fe64d9d..a503272 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -615,6 +615,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Щоб продовжити, скористайтеся відбитком пальця або даними для розблокування екрана"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Сталася помилка. Повторіть спробу."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок відбитка пальця"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейсконтроль"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Сталася помилка з фейсконтролем"</string>
@@ -667,6 +668,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Щоб продовжити, скористайтеся фейсконтролем або даними для розблокування екрана"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Сталася помилка. Повторіть спробу."</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"Значок обличчя"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"читати налаштування синхронізації"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дозволяє програмі читати налаштування синхронізації для облікового запису, наприклад, визначати, чи програма Люди синхронізується з обліковим записом."</string>
@@ -1736,7 +1738,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Якщо цей засіб увімкнено, ви можете активувати спеціальні можливості, утримуючи обидві кнопки гучності протягом трьох секунд."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Увімкнути засіб спеціальних можливостей?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Якщо втримувати обидві клавіші гучності впродовж кількох секунд, вмикаються спеціальні можливості. Це впливає на роботу пристрою.\n\nПоточні функції:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nВибрані функції можна змінити в налаштуваннях у меню спеціальних можливостей."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Увімкнути засіб швидкого доступу до сервісу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Якщо втримувати обидві клавіші гучності впродовж кількох секунд, буде ввімкнено спеціальні можливості – <xliff:g id="SERVICE">%1$s</xliff:g>. Це може вплинути на роботу пристрою.\n\nДля цієї комбінації клавіш можна вибрати іншу функцію в меню \"Налаштування &gt; Спеціальні можливості\"."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Увімкнути"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index de5a301..d450667 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"جاری رکھنے کے لیے اپنے فنگر پرنٹ یا اسکرین لاک کا استعمال کریں"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"فنگر پرنٹ آئیکن"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"فیس اَنلاک"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"فیس اَنلاک میں مسئلہ"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"جاری رکھنے کے لیے اپنے چہرے یا اسکرین لاک کا استعمال کریں"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"چہرے کا آئیکن"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"مطابقت پذیری کی ترتیبات پڑھیں"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"‏ایپ کو کسی اکاؤنٹ کیلئے مطابقت پذیری کی ترتیبات پڑھنے کی اجازت دیتا ہے۔ مثلا، یہ تعین کرسکتا ہے کہ آیا People ایپ کسی اکاؤنٹ کے ساتھ مطابقت پذیر ہے۔"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ایکسیسبیلٹی خصوصیات کے لیے شارٹ کٹ آن کریں؟"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"دونوں والیوم کی کلیدوں کو کچھ سیکنڈز تک دبائیں رکھنے سے ایکسیسبیلٹی خصوصیات آن ہو جاتی ہیں۔ اس سے آپ کے آلے کے کام کرنے کا طریقہ تبدیل ہو سکتا ہے۔\n\nموجودہ خصوصیات:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nآپ ترتیبات اور ایکسیسبیلٹی میں منتخب کردہ خصوصیات کو تبدیل کر سکتے ہیں۔"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> شارٹ کٹ آن کریں؟"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"والیوم کی دونوں کلیدوں کو کچھ سیکنڈز تک دبائے رکھنے سے <xliff:g id="SERVICE">%1$s</xliff:g> ایکسیسبیلٹی خصوصیت آن ہو جاتی ہے۔ اس سے آپ کے آلے کے کام کرنے کا طریقہ تبدیل ہو سکتا ہے۔\n\nآپ ترتیبات اور ایکسیسبیلٹی میں دیگر خصوصیت کے لیے اس شارٹ کٹ کو تبدیل کر سکتے ہیں۔"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"آن کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index ecc5f52..f5a8fed2 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Davom etish uchun barmoq izi yoki ekran qulfidan foydalaning"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmoq izi belgisi"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Yuz bilan ochish"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Yuz bilan ochishda muammo bor"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davom etish uchun yuz tekshiruvi yoki ekran qulfidan foydalaning"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Yuz belgisi"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"sinx-sh sozlamalarini o‘qish"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ilovaga hisobning sinxronlash sozlamalarini o‘qish uchun ruxsat beradi. Masalan, bu \"Odamlar\" ilovasi hisob bilan sinxronlangan yoki aksini aniqlay oladi."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala tovush tugmasini 3 soniya bosib turing."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Maxsus imkoniyatlar uchun tezkor tugma yoqilsinmi?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Maxsus imkoniyatlarni yoqish uchun ikkala tovush tugmalarini bir necha soniya bosib turing. Qurilmangiz ishlashida oʻzgarish yuz berishi mumkin.\n\nJoriy funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nTanlangan funksiyalarni Sozlamalar ichidagi Maxsus imkoniyatlar ustiga bosib oʻzgartirishingiz mumkin."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> tezkor tugmasi yoqilsinmi?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> funksiyasini yoqish uchun ikkala tovush tugmalarini bir necha soniya bosib turing. Qurilmangiz ishlashida oʻzgarish yuz berishi mumkin.\n\nBu tezkor tugmalarni boshqa funksiyaga Sozlamalar ichidagi Maxsus imkoniyatlar orqali tayinlash mumkin."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Yoqilsin"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 38a424b..31a2605 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Dùng vân tay của bạn hoặc phương thức khóa màn hình để tiếp tục"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Biểu tượng vân tay"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Mở khóa bằng khuôn mặt"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Vấn đề với tính năng Mở khóa bằng khuôn mặt"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Dùng khuôn mặt của bạn hoặc phương thức khóa màn hình để tiếp tục"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Biểu tượng khuôn mặt"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"đọc cài đặt đồng bộ hóa"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Cho phép ứng dụng đọc cài đặt đồng bộ hóa cho tài khoản. Ví dụ: việc này có thể xác định liệu ứng dụng Mọi người đã được đồng bộ hóa với tài khoản chưa."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Khi phím tắt này đang bật, thao tác nhấn cả hai nút âm lượng trong 3 giây sẽ mở tính năng hỗ trợ tiếp cận."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Bật phím tắt cho các tính năng hỗ trợ tiếp cận?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Thao tác nhấn và giữ cả hai phím âm lượng trong vài giây sẽ bật các tính năng hỗ trợ tiếp cận. Việc bật các tính năng này có thể thay đổi cách thiết bị của bạn hoạt động.\n\nCác tính năng hiện tại:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nBạn có thể thay đổi những tính năng đã chọn trong phần Cài đặt &gt; Hỗ trợ tiếp cận."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Bật phím tắt cho <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Thao tác nhấn và giữ cả hai phím âm lượng trong vài giây sẽ bật <xliff:g id="SERVICE">%1$s</xliff:g>, một tính năng hỗ trợ tiếp cận. Việc bật tính năng này có thể thay đổi cách thiết bị của bạn hoạt động.\n\nBạn có thể chuyển phím tắt này thành một tính năng khác trong phần Cài đặt &gt; Hỗ trợ tiếp cận."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Bật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index ea66619..26c2b25 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -327,17 +327,17 @@
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"身体传感器"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"访问与您的生命体征相关的传感器数据"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"检索窗口内容"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"检测您正访问的窗口的内容。"</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"检测您与之互动的窗口的内容。"</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"启用触摸浏览"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"设备将大声读出您点按的内容,同时您可以通过手势来浏览屏幕。"</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"监测您输入的文字"</string>
-    <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"包含个人数据,例如信用卡号和密码。"</string>
-    <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"控制显示内容放大功能"</string>
-    <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"控制显示内容的缩放级别和位置。"</string>
+    <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"包括信用卡号和密码等个人数据。"</string>
+    <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"控制屏幕内容放大功能"</string>
+    <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"控制屏幕内容的缩放级别和位置。"</string>
     <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"执行手势"</string>
     <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"可执行点按、滑动、双指张合等手势。"</string>
     <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"指纹手势"</string>
-    <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"可以捕获在设备指纹传感器上执行的手势。"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"可以捕捉在设备指纹传感器上执行的手势。"</string>
     <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"截取屏幕截图"</string>
     <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"可截取显示画面的屏幕截图。"</string>
     <string name="permlab_statusBar" msgid="8798267849526214017">"停用或修改状态栏"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"使用指纹解锁或屏幕锁定凭据验证身份,才能继续操作"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指纹图标"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"人脸解锁"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"人脸解锁存在问题"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"使用人脸解锁或屏幕锁定凭据验证身份,才能继续操作"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"面孔图标"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"读取同步设置"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允许该应用读取某个帐号的同步设置。例如,此权限可确定“联系人”应用是否与某个帐号同步。"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"启用这项快捷方式后,同时按下两个音量按钮 3 秒钟即可启动无障碍功能。"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要开启无障碍功能快捷方式吗?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同时按住两个音量键几秒钟,即可开启无障碍功能。这样做可能会改变您设备的工作方式。\n\n当前功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n您可以在“设置”&gt;“无障碍”中更改所选功能。"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要开启<xliff:g id="SERVICE">%1$s</xliff:g>快捷方式吗?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同时按住两个音量键几秒钟,即可开启<xliff:g id="SERVICE">%1$s</xliff:g>无障碍功能。这样做可能会改变您设备的工作方式。\n\n您可以在“设置”&gt;“无障碍”中将此快捷方式更改为开启另一项功能。"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"开启"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index ccfb026..b87d7c0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -609,6 +609,7 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"請使用指紋解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"發生錯誤,請再試一次。"</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"面孔解鎖"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"「面孔解鎖」功能發生問題"</string>
@@ -661,6 +662,7 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用面孔解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <string name="face_error_vendor_unknown" msgid="7387005932083302070">"發生錯誤,請再試一次。"</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步設定,例如確定「通訊錄」應用程式是否和某個帳戶保持同步。"</string>
@@ -1692,7 +1694,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用快速鍵後,同時按住音量按鈕 3 秒便可啟用無障礙功能。"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要開啟無障礙功能捷徑嗎?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同時按下兩個音量鍵幾秒,以開啟無障礙功能。這可能會變更裝置的運作。\n\n目前功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n您可在「設定」&gt;「無障礙功能」中變更所選功能。"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要開啟 <xliff:g id="SERVICE">%1$s</xliff:g> 捷徑嗎?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同時按下兩個音量鍵幾秒,以開啟 <xliff:g id="SERVICE">%1$s</xliff:g> 無障礙功能。這可能會變更裝置的運作。\n\n您可在「設定」&gt;「無障礙功能」中變更此快速鍵。"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"開啟"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d6c98c5..4fb2225 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -246,7 +246,7 @@
     <string name="global_action_power_off" msgid="4404936470711393203">"關機"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"電源"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"重新啟動"</string>
-    <string name="global_action_emergency" msgid="1387617624177105088">"緊急電話"</string>
+    <string name="global_action_emergency" msgid="1387617624177105088">"緊急撥號"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"錯誤報告"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"結束"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"螢幕截圖"</string>
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"請使用指紋解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"人臉解鎖"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"人臉解鎖功能發生問題"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用人臉解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用捷徑功能,只要同時按下兩個音量按鈕 3 秒,就能啟動無障礙功能。"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要開啟無障礙功能快速鍵嗎?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同時按住音量調高鍵和調低鍵數秒,即可開啟無障礙功能。這麼做可能會改變裝置的運作方式。\n\n目前的功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n你可以在 [設定] &gt; [無障礙設定] 中變更選取的功能。"</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」快速鍵嗎?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同時按住音量調高鍵和調低鍵數秒,即可開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」無障礙功能。這麼做可能會改變裝置的運作方式。\n\n你可以在 [設定] &gt; [無障礙設定] 中變更這個快速鍵觸發的功能。"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"開啟"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9c9d68a..ae0cbe2 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -609,6 +609,8 @@
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Sebenzisa izigxivizo zakho zomunwe noma ukukhiya isikrini ukuze uqhubeke"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
+    <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+    <skip />
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Isithonjana sezigxivizo zeminwe"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ukuvula ubuso"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Inkinga Ngokuvula ngobuso"</string>
@@ -661,6 +663,8 @@
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Sebenzisa ubuso bakho noma ukukhiya isikrini ukuze uqhubeke"</string>
   <string-array name="face_error_vendor">
   </string-array>
+    <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+    <skip />
     <string name="face_icon_content_description" msgid="465030547475916280">"Isithonjana sobuso"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"funda izilungiselelo zokuvumelanisa"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ivumela uhlelo lokusebenza ukufunda izilungiselelo zokuvumelanisa ze-akhawunti. Isibonelo, lokhu kungacacisa ukuthi noma ngabe uhlelo lokusebenza le-People livumelanisiwe ne-akhawunti."</string>
@@ -1692,7 +1696,8 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Uma isinqamuleli sivuliwe, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqalisa isici sokufinyelela."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vula isinqamuleli sezici zokufinyeleleka?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ukubambela phansi bobabili okhiye bevolumu amasekhondi ambalwa kuvula izici zokufinyelela. Lokhu kungashintsha indlela idivayisi yakho esebenza ngayo.\n\nIzici zamanje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nUngashintsha izici ezikhethiwe Kuzilungiselelo &gt; Ukufinyeleleka."</string>
-    <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+    <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+    <skip />
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vula isinqamuleli se-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ukubambela phansi bobabili okhiye bevolumu amasekhondi ambalwa kuvula i-<xliff:g id="SERVICE">%1$s</xliff:g>, eyisici sokufinyelela Lokhu kungashintsha indlela idivayisi yakho esebenza ngayo.\n\nUngashintshela lesi sinqamuleli kwesinye isici Kuzilungiselelo &gt; Ukufinyeleleka."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Vula"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a5f5051..a56ed14 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8658,6 +8658,8 @@
         <attr name="successColor" format="color|reference"/>
         <!-- The dot color -->
         <attr name="dotColor" format="color|reference"/>
+        <!-- Color of the dot when it's activated -->
+        <attr name="dotActivatedColor" format="color|reference"/>
 
     </declare-styleable>
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 73dfab6..fc9b55f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -395,6 +395,12 @@
          this attribute unnecessary. -->
     <attr name="sharedUserLabel" format="reference" />
 
+    <!-- The maximum device SDK version for which the application will remain in the user ID
+         defined in sharedUserId. Used when the application wants to migrate out of using shared
+         user ID, but has to maintain backwards compatibility with the API level specified
+         and before. -->
+    <attr name="sharedUserMaxSdkVersion" format="integer" />
+
     <!-- Internal version code.  This is the number used to determine whether
          one version is more recent than another: it has no other meaning than
          that higher numbers are more recent.  You could use this number to
@@ -1218,6 +1224,22 @@
          resource] to be present in order to function. Default value is false. -->
     <attr name="isSplitRequired" format="boolean" />
 
+    <!-- List of split types required by this APK to be present in order to function properly,
+         separated by commas. The platform will reject installation of an app that is missing
+         any required split types. Each split type is a string, and is only used for matching
+         <code>requiredSplitTypes</code> and <code>splitTypes</code>. As an example, if this
+         APK requires localized string resources, screen density resources, and native code
+         this value could be "language,density,abi". Default value is null to indicate no split
+         types are required. -->
+    <attr name="requiredSplitTypes" format="string" />
+
+    <!-- List of split types offered by this APK, separated by commas. Each split type is a
+         string, and is only used for matching <code>requiredSplitTypes</code> and
+         <code>splitTypes</code>. As an example, if this split offers localized string resources,
+         and screen density resources the value could be "language,density". Default value is
+         null to indicate no split types are offered. -->
+    <attr name="splitTypes" format="string" />
+
     <!-- Flag to specify if this app wants to run the dex within its APK but not extracted or
          locally compiled variants. This keeps the dex code protected by the APK signature. Such
          apps will always run in JIT mode (same when they are first installed), and the system will
@@ -1650,6 +1672,7 @@
         <attr name="revisionCode" />
         <attr name="sharedUserId" />
         <attr name="sharedUserLabel" />
+        <attr name="sharedUserMaxSdkVersion" />
         <attr name="installLocation" />
         <attr name="isolatedSplits" />
         <attr name="isFeatureSplit" />
@@ -1657,6 +1680,8 @@
         <attr name="compileSdkVersion" />
         <attr name="compileSdkVersionCodename" />
         <attr name="isSplitRequired" />
+        <attr name="requiredSplitTypes" />
+        <attr name="splitTypes" />
     </declare-styleable>
 
     <!-- The <code>application</code> tag describes application-level components
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 55ed83b..b191584 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -248,37 +248,37 @@
     <color name="system_accent1_0">#ffffff</color>
     <!-- Shade of the accent system color at 99% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_10">#F1FFFC</color>
+    <color name="system_accent1_10">#F9FCFF</color>
     <!-- Shade of the accent system color at 95% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_50">#9CFFF2</color>
+    <color name="system_accent1_50">#E0F3FF</color>
     <!-- Shade of the accent system color at 90% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_100">#8DF5E3</color>
+    <color name="system_accent1_100">#C1E8FF</color>
     <!-- Shade of the accent system color at 80% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_200">#71D8C7</color>
+    <color name="system_accent1_200">#76D1FF</color>
     <!-- Shade of the accent system color at 70% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_300">#53BCAC</color>
+    <color name="system_accent1_300">#4BB6E8</color>
     <!-- Shade of the accent system color at 60% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_400">#34A192</color>
+    <color name="system_accent1_400">#219BCC</color>
     <!-- Shade of the accent system color at 49% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_500">#008375</color>
+    <color name="system_accent1_500">#007FAC</color>
     <!-- Shade of the accent system color at 40% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_600">#006C5F</color>
+    <color name="system_accent1_600">#00668B</color>
     <!-- Shade of the accent system color at 30% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_700">#005747</color>
+    <color name="system_accent1_700">#004C69</color>
     <!-- Shade of the accent system color at 20% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_800">#003E31</color>
+    <color name="system_accent1_800">#003549</color>
     <!-- Shade of the accent system color at 10% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent1_900">#002214</color>
+    <color name="system_accent1_900">#001E2C</color>
     <!-- Darkest shade of the accent color used by the system. Black.
      This value can be overlaid at runtime by OverlayManager RROs. -->
     <color name="system_accent1_1000">#000000</color>
@@ -288,37 +288,37 @@
     <color name="system_accent2_0">#ffffff</color>
     <!-- Shade of the secondary accent system color at 99% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_10">#F0FFFC</color>
+    <color name="system_accent2_10">#F9FCFF</color>
     <!-- Shade of the secondary accent system color at 95% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_50">#CDFAF1</color>
+    <color name="system_accent2_50">#E0F3FF</color>
     <!-- Shade of the secondary accent system color at 90% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_100">#BFEBE3</color>
+    <color name="system_accent2_100">#D1E5F4</color>
     <!-- Shade of the secondary accent system color at 80% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_200">#A4CFC7</color>
+    <color name="system_accent2_200">#B5CAD7</color>
     <!-- Shade of the secondary accent system color at 70% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_300">#89B4AC</color>
+    <color name="system_accent2_300">#9AAEBB</color>
     <!-- Shade of the secondary accent system color at 60% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_400">#6F9991</color>
+    <color name="system_accent2_400">#8094A0</color>
     <!-- Shade of the secondary accent system color at 49% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_500">#537C75</color>
+    <color name="system_accent2_500">#657985</color>
     <!-- Shade of the secondary accent system color at 40% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_600">#3D665F</color>
+    <color name="system_accent2_600">#4E616C</color>
     <!-- Shade of the secondary accent system color at 30% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_700">#254E47</color>
+    <color name="system_accent2_700">#374955</color>
     <!-- Shade of the secondary accent system color at 20% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_800">#0C3731</color>
+    <color name="system_accent2_800">#20333D</color>
     <!-- Shade of the secondary accent system color at 10% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent2_900">#00211C</color>
+    <color name="system_accent2_900">#091E28</color>
     <!-- Darkest shade of the secondary accent color used by the system. Black.
      This value can be overlaid at runtime by OverlayManager RROs. -->
     <color name="system_accent2_1000">#000000</color>
@@ -331,34 +331,34 @@
     <color name="system_accent3_10">#FFFBFF</color>
     <!-- Shade of the tertiary accent system color at 95% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_50">#F9EAFF</color>
+    <color name="system_accent3_50">#F5EEFF</color>
     <!-- Shade of the tertiary accent system color at 90% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_100">#ECDBFF</color>
+    <color name="system_accent3_100">#E6DEFF</color>
     <!-- Shade of the tertiary accent system color at 80% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_200">#CFBFEB</color>
+    <color name="system_accent3_200">#CAC1EA</color>
     <!-- Shade of the tertiary accent system color at 70% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_300">#B3A4CF</color>
+    <color name="system_accent3_300">#AEA6CE</color>
     <!-- Shade of the tertiary accent system color at 60% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_400">#988AB3</color>
+    <color name="system_accent3_400">#938CB1</color>
     <!-- Shade of the tertiary accent system color at 49% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_500">#7B6E96</color>
+    <color name="system_accent3_500">#787296</color>
     <!-- Shade of the tertiary accent system color at 40% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_600">#64587F</color>
+    <color name="system_accent3_600">#605A7C</color>
     <!-- Shade of the tertiary accent system color at 30% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_700">#4C4165</color>
+    <color name="system_accent3_700">#484264</color>
     <!-- Shade of the tertiary accent system color at 20% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_800">#352B4D</color>
+    <color name="system_accent3_800">#322C4C</color>
     <!-- Shade of the tertiary accent system color at 10% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_accent3_900">#1E1636</color>
+    <color name="system_accent3_900">#1D1736</color>
     <!-- Darkest shade of the tertiary accent color used by the system. Black.
      This value can be overlaid at runtime by OverlayManager RROs. -->
     <color name="system_accent3_1000">#000000</color>
@@ -368,37 +368,37 @@
     <color name="system_neutral1_0">#ffffff</color>
     <!-- Shade of the neutral system color at 99% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_10">#fbfbfb</color>
+    <color name="system_neutral1_10">#FCFCFF</color>
     <!-- Shade of the neutral system color at 95% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_50">#f0f0f0</color>
+    <color name="system_neutral1_50">#F0F0F3</color>
     <!-- Shade of the neutral system color at 90% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_100">#e2e2e2</color>
+    <color name="system_neutral1_100">#E1E3E5</color>
     <!-- Shade of the neutral system color at 80% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_200">#c6c6c6</color>
+    <color name="system_neutral1_200">#C5C7C9</color>
     <!-- Shade of the neutral system color at 70% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_300">#ababab</color>
+    <color name="system_neutral1_300">#AAABAE</color>
     <!-- Shade of the neutral system color at 60% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_400">#909090</color>
+    <color name="system_neutral1_400">#8F9193</color>
     <!-- Shade of the neutral system color at 49% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_500">#757575</color>
+    <color name="system_neutral1_500">#747679</color>
     <!-- Shade of the neutral system color at 40% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_600">#5e5e5e</color>
+    <color name="system_neutral1_600">#5C5F61</color>
     <!-- Shade of the neutral system color at 30% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_700">#464646</color>
+    <color name="system_neutral1_700">#454749</color>
     <!-- Shade of the neutral system color at 20% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_800">#303030</color>
+    <color name="system_neutral1_800">#2E3133</color>
     <!-- Shade of the neutral system color at 10% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral1_900">#1b1b1b</color>
+    <color name="system_neutral1_900">#191C1E</color>
     <!-- Darkest shade of the neutral color used by the system. Black.
      This value can be overlaid at runtime by OverlayManager RROs. -->
     <color name="system_neutral1_1000">#000000</color>
@@ -408,37 +408,37 @@
     <color name="system_neutral2_0">#ffffff</color>
     <!-- Shade of the secondary neutral system color at 99% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_10">#fbfbfb</color>
+    <color name="system_neutral2_10">#F9FCFF</color>
     <!-- Shade of the secondary neutral system color at 95% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_50">#f0f0f0</color>
+    <color name="system_neutral2_50">#EBF1F8</color>
     <!-- Shade of the secondary neutral system color at 90% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_100">#e2e2e2</color>
+    <color name="system_neutral2_100">#DCE3E9</color>
     <!-- Shade of the secondary neutral system color at 80% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_200">#c6c6c6</color>
+    <color name="system_neutral2_200">#C0C7CD</color>
     <!-- Shade of the secondary neutral system color at 70% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_300">#ababab</color>
+    <color name="system_neutral2_300">#A5ACB2</color>
     <!-- Shade of the secondary neutral system color at 60% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_400">#909090</color>
+    <color name="system_neutral2_400">#8A9297</color>
     <!-- Shade of the secondary neutral system color at 49% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_500">#757575</color>
+    <color name="system_neutral2_500">#70777C</color>
     <!-- Shade of the secondary neutral system color at 40% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_600">#5e5e5e</color>
+    <color name="system_neutral2_600">#585F65</color>
     <!-- Shade of the secondary neutral system color at 30% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_700">#464646</color>
+    <color name="system_neutral2_700">#40484D</color>
     <!-- Shade of the secondary neutral system color at 20% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_800">#303030</color>
+    <color name="system_neutral2_800">#2A3136</color>
     <!-- Shade of the secondary neutral system color at 10% lightness.
      This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_neutral2_900">#1b1b1b</color>
+    <color name="system_neutral2_900">#161C20</color>
     <!-- Darkest shade of the secondary neutral color used by the system. Black.
      This value can be overlaid at runtime by OverlayManager RROs. -->
     <color name="system_neutral2_1000">#000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5cd3138..a378d14 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -660,6 +660,9 @@
     <!-- Indicates whether to enable an animation when unfolding a device or not -->
     <bool name="config_unfoldTransitionEnabled">false</bool>
 
+    <!-- Indicates whether to enable hinge angle sensor when using unfold animation -->
+    <bool name="config_unfoldTransitionHingeAngle">false</bool>
+
     <!-- Indicates that the device supports having more than one internal display on at the same
          time. Only applicable to devices with more than one internal display. If this option is
          set to false, DisplayManager will make additional effort to ensure no more than 1 internal
@@ -971,6 +974,20 @@
     -->
     <integer name="config_longPressOnPowerBehavior">5</integer>
 
+    <!-- The time in milliseconds after which a press on power button is considered "long". -->
+    <integer name="config_longPressOnPowerDurationMs">500</integer>
+
+    <!-- The possible UI options to be surfaced for configuring long press power on duration
+         action. Value set in config_longPressOnPowerDurationMs should be one of the available
+         options to allow users to restore default. -->
+    <integer-array name="config_longPressOnPowerDurationSettings">
+        <item>250</item>
+        <item>350</item>
+        <item>500</item>
+        <item>650</item>
+        <item>750</item>
+    </integer-array>
+
     <!-- Whether the setting to change long press on power behaviour from default to assistant (5)
          is available in Settings.
      -->
@@ -1439,6 +1456,14 @@
     <integer-array name="config_autoBrightnessLcdBacklightValues">
     </integer-array>
 
+    <!-- Array of output values for LCD backlight in doze mode corresponding to the lux values
+         in the config_autoBrightnessLevels array.  This array should have size one greater
+         than the size of the config_autoBrightnessLevels array.
+         The brightness values must be between 0 and 255 and be non-decreasing.
+         This must be overridden in platform specific overlays -->
+    <integer-array name="config_autoBrightnessLcdBacklightValues_doze">
+    </integer-array>
+
     <!-- Array of desired screen brightness in nits corresponding to the lux values
          in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and
          config_screenBrightnessMaximumNits, the display brightness is defined as the measured
@@ -4865,9 +4890,8 @@
             - Option 3 is selected for R.integer.config_letterboxBackgroundType and blur requested
             but isn't supported on the device or both dark scrim alpha and blur radius aren't
             provided.
-        Defaults to black if not specified.
      -->
-    <color name="config_letterboxBackgroundColor">#000</color>
+    <color name="config_letterboxBackgroundColor">@android:color/system_neutral2_500</color>
 
     <!-- Horizonal position of a center of the letterboxed app window.
         0 corresponds to the left side of the screen and 1 to the right side. If given value < 0
@@ -5113,6 +5137,14 @@
            - config_fillBuiltInDisplayCutoutArray
            - config_maskBuiltInDisplayCutoutArray
            - config_waterfallCutoutArray
+           - config_roundedCornerRadiusArray
+           - config_roundedCornerTopRadiusArray
+           - config_roundedCornerBottomRadiusArray
+           - config_builtInDisplayIsRoundArray (config in SystemUI resource)
+           - config_roundedCornerMultipleRadiusArray (config in SystemUI resource)
+           - config_roundedCornerDrawableArray (config in SystemUI resource)
+           - config_roundedCornerTopDrawableArray (config in SystemUI resource)
+           - config_roundedCornerBottomDrawableArray (config in SystemUI resource)
 
          Leave this array empty for single display device and the system will load the default main
          built-in related configs.
@@ -5174,4 +5206,54 @@
          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>
+
+    <!-- Wear OS: the name of the package containing the device's sysui. -->
+    <string name="config_wearSysUiPackage" translatable="false"/>
+
+    <!-- Wear OS: the name of the main activity of the device's sysui. -->
+    <string name="config_wearSysUiMainActivity" translatable="false"/>
+
+    <bool name="config_secondaryBuiltInDisplayIsRound">@bool/config_windowIsRound</bool>
+
+    <!-- The display round config for each display in a multi-display device. -->
+    <array name="config_builtInDisplayIsRoundArray" translatable="false">
+        <item>@bool/config_mainBuiltInDisplayIsRound</item>
+        <item>@bool/config_secondaryBuiltInDisplayIsRound</item>
+    </array>
+
+    <!-- The rounded corner radius for each display in a multi-display device. -->
+    <array name="config_roundedCornerRadiusArray" translatable="false">
+        <item>@dimen/rounded_corner_radius</item>
+        <item>@dimen/secondary_rounded_corner_radius</item>
+    </array>
+
+    <!-- The top rounded corner radius for each display in a multi-display device. -->
+    <array name="config_roundedCornerTopRadiusArray" translatable="false">
+        <item>@dimen/rounded_corner_radius_top</item>
+        <item>@dimen/secondary_rounded_corner_radius_top</item>
+    </array>
+
+    <!-- The bottom rounded corner radius for each display in a multi-display device. -->
+    <array name="config_roundedCornerBottomRadiusArray" translatable="false">
+        <item>@dimen/rounded_corner_radius_bottom</item>
+        <item>@dimen/secondary_rounded_corner_radius_bottom</item>
+    </array>
+
+    <!-- The rounded corner radius adjustment for each display in a multi-display device. -->
+    <array name="config_roundedCornerRadiusAdjustmentArray" translatable="false">
+        <item>@dimen/rounded_corner_radius_adjustment</item>
+        <item>@dimen/secondary_rounded_corner_radius_adjustment</item>
+    </array>
+
+    <!-- The rounded corner radius top adjustment for each display in a multi-display device. -->
+    <array name="config_roundedCornerTopRadiusAdjustmentArray" translatable="false">
+        <item>@dimen/rounded_corner_radius_top_adjustment</item>
+        <item>@dimen/secondary_rounded_corner_radius_top_adjustment</item>
+    </array>
+
+    <!-- The rounded corner radius bottom adjustment for each display in a multi-display device. -->
+    <array name="config_roundedCornerBottomRadiusAdjustmentArray" translatable="false">
+        <item>@dimen/rounded_corner_radius_bottom_adjustment</item>
+        <item>@dimen/secondary_rounded_corner_radius_bottom_adjustment</item>
+    </array>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e8bb606..313c4da 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -55,6 +55,8 @@
     <dimen name="navigation_bar_height_landscape">48dp</dimen>
     <!-- Width of the navigation bar when it is placed vertically on the screen -->
     <dimen name="navigation_bar_width">48dp</dimen>
+    <!-- Height of the bottom taskbar not including decorations like rounded corners. -->
+    <dimen name="taskbar_frame_height">60dp</dimen>
     <!-- How much we expand the touchable region of the status bar below the notch to catch touches
          that just start below the notch. -->
     <dimen name="display_cutout_touchable_region_size">12dp</dimen>
@@ -641,6 +643,8 @@
     <dimen name="lock_pattern_dot_line_width">22dp</dimen>
     <dimen name="lock_pattern_dot_size">14dp</dimen>
     <dimen name="lock_pattern_dot_size_activated">30dp</dimen>
+    <!-- Width of a gradient applied to a lock pattern line while its disappearing animation. -->
+    <dimen name="lock_pattern_fade_away_gradient_width">8dp</dimen>
 
     <dimen name="text_handle_min_size">40dp</dimen>
 
@@ -952,4 +956,12 @@
     <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>
+
+    <!-- Rounded corner settings for secondary built-in display -->
+    <dimen name="secondary_rounded_corner_radius">0px</dimen>
+    <dimen name="secondary_rounded_corner_radius_top">0px</dimen>
+    <dimen name="secondary_rounded_corner_radius_bottom">0px</dimen>
+    <dimen name="secondary_rounded_corner_radius_adjustment">0px</dimen>
+    <dimen name="secondary_rounded_corner_radius_top_adjustment">0px</dimen>
+    <dimen name="secondary_rounded_corner_radius_bottom_adjustment">0px</dimen>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index c4838b8..84f82fd 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -254,6 +254,15 @@
   <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER}. -->
   <item type="id" name="accessibilityActionImeEnter" />
 
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. -->
+  <item type="id" name="accessibilityActionDragStart" />
+
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_DROP}. -->
+  <item type="id" name="accessibilityActionDragDrop" />
+
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_CANCEL}. -->
+  <item type="id" name="accessibilityActionDragCancel" />
+
   <!-- View tag for remote views to store the index of the next child when adding nested remote views dynamically. -->
   <item type="id" name="remote_views_next_child" />
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a519cde..e28288d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3224,6 +3224,9 @@
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01fe0000">
+    <public name="accessibilityActionDragStart" />
+    <public name="accessibilityActionDragDrop" />
+    <public name="accessibilityActionDragCancel" />
   </staging-public-group>
 
   <staging-public-group type="style" first-id="0x01fd0000">
@@ -3295,6 +3298,9 @@
   <eat-comment />
 
   <staging-public-group type="attr" first-id="0x01df0000">
+    <public name="sharedUserMaxSdkVersion" />
+    <public name="requiredSplitTypes" />
+    <public name="splitTypes" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d2c6f78..4c1cc87 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1650,6 +1650,8 @@
     <!-- Array containing custom error messages from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="fingerprint_error_vendor">
     </string-array>
+    <!-- Default error message to use when fingerprint_error_vendor does not contain a message. [CHAR LIMIT=NONE] -->
+    <string name="fingerprint_error_vendor_unknown">Something went wrong. Try again.</string>
 
     <!-- Content description which should be used for the fingerprint icon. -->
     <string name="fingerprint_icon_content_description">Fingerprint icon</string>
@@ -1760,6 +1762,8 @@
     <!-- Array containing custom error messages from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="face_error_vendor">
     </string-array>
+    <!-- Default error message to use when face_error_vendor does not contain a message. [CHAR LIMIT=NONE] -->
+    <string name="face_error_vendor_unknown">Something went wrong. Try again.</string>
 
     <!-- Content description which should be used for the face icon. [CHAR LIMIT=10] -->
     <string name="face_icon_content_description">Face icon</string>
@@ -4557,7 +4561,7 @@
     <string name="accessibility_shortcut_multiple_service_warning">Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="service" example="TalkBack">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility.</string>
 
     <!-- Used in multiple service warning to list current features. [CHAR LIMIT=none] -->
-    <string name="accessibility_shortcut_multiple_service_list">\t• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
+    <string name="accessibility_shortcut_multiple_service_list">\u0020• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
 
     <!-- Dialog title for dialog shown when this accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
     <string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g> shortcut?</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0daf358..7dd94f2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -439,6 +439,8 @@
   <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_immersive_mode_confirmation_panic" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
+  <java-symbol type="integer" name="config_longPressOnPowerDurationMs" />
+  <java-symbol type="array" name="config_longPressOnPowerDurationSettings" />
   <java-symbol type="bool" name="config_longPressOnPowerForAssistantSettingAvailable" />
   <java-symbol type="integer" name="config_veryLongPressOnPowerBehavior" />
   <java-symbol type="integer" name="config_veryLongPressTimeout" />
@@ -1316,6 +1318,7 @@
   <java-symbol type="dimen" name="lock_pattern_dot_line_width" />
   <java-symbol type="dimen" name="lock_pattern_dot_size" />
   <java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
+  <java-symbol type="dimen" name="lock_pattern_fade_away_gradient_width" />
   <java-symbol type="drawable" name="clock_dial" />
   <java-symbol type="drawable" name="clock_hand_hour" />
   <java-symbol type="drawable" name="clock_hand_minute" />
@@ -1740,6 +1743,7 @@
   <java-symbol type="dimen" name="navigation_bar_height_car_mode" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape_car_mode" />
   <java-symbol type="dimen" name="navigation_bar_width_car_mode" />
+  <java-symbol type="dimen" name="taskbar_frame_height" />
   <java-symbol type="dimen" name="status_bar_height" />
   <java-symbol type="dimen" name="display_cutout_touchable_region_size" />
   <java-symbol type="dimen" name="quick_qs_offset_height" />
@@ -1883,6 +1887,7 @@
   <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
+  <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues_doze" />
   <java-symbol type="array" name="config_autoBrightnessLevels" />
   <java-symbol type="array" name="config_ambientThresholdLevels" />
   <java-symbol type="array" name="config_ambientBrighteningThresholds" />
@@ -2525,6 +2530,7 @@
   <java-symbol type="string" name="fingerprint_error_no_space" />
   <java-symbol type="string" name="fingerprint_error_timeout" />
   <java-symbol type="array" name="fingerprint_error_vendor" />
+  <java-symbol type="string" name="fingerprint_error_vendor_unknown" />
   <java-symbol type="string" name="fingerprint_acquired_partial" />
   <java-symbol type="string" name="fingerprint_acquired_insufficient" />
   <java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
@@ -2564,6 +2570,7 @@
   <java-symbol type="string" name="face_error_no_space" />
   <java-symbol type="string" name="face_error_timeout" />
   <java-symbol type="array" name="face_error_vendor" />
+  <java-symbol type="string" name="face_error_vendor_unknown" />
   <java-symbol type="string" name="face_error_canceled" />
   <java-symbol type="string" name="face_error_user_canceled" />
   <java-symbol type="string" name="face_error_lockout" />
@@ -3841,6 +3848,7 @@
   <java-symbol type="string" name="config_foldedArea" />
   <java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
   <java-symbol type="bool" name="config_unfoldTransitionEnabled" />
+  <java-symbol type="bool" name="config_unfoldTransitionHingeAngle" />
   <java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
 
 
@@ -4469,4 +4477,22 @@
   <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" />
+
+  <java-symbol type="string" name="config_wearSysUiPackage"/>
+  <java-symbol type="string" name="config_wearSysUiMainActivity"/>
+
+  <java-symbol type="dimen" name="secondary_rounded_corner_radius" />
+  <java-symbol type="dimen" name="secondary_rounded_corner_radius_top" />
+  <java-symbol type="dimen" name="secondary_rounded_corner_radius_bottom" />
+  <java-symbol type="dimen" name="secondary_rounded_corner_radius_adjustment" />
+  <java-symbol type="dimen" name="secondary_rounded_corner_radius_top_adjustment" />
+  <java-symbol type="dimen" name="secondary_rounded_corner_radius_bottom_adjustment" />
+  <java-symbol type="array" name="config_roundedCornerRadiusArray" />
+  <java-symbol type="array" name="config_roundedCornerTopRadiusArray" />
+  <java-symbol type="array" name="config_roundedCornerBottomRadiusArray" />
+  <java-symbol type="array" name="config_roundedCornerRadiusAdjustmentArray" />
+  <java-symbol type="array" name="config_roundedCornerTopRadiusAdjustmentArray" />
+  <java-symbol type="array" name="config_roundedCornerBottomRadiusAdjustmentArray" />
+  <java-symbol type="bool" name="config_secondaryBuiltInDisplayIsRound" />
+  <java-symbol type="array" name="config_builtInDisplayIsRoundArray" />
 </resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 37d059a..69d2c74 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -274,6 +274,6 @@
     <shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" />
 
     <!-- South Africa -->
-    <shortcode country="za" pattern="\d{1,5}" free="44136|30791|36056" />
+    <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056" />
 
 </shortcodes>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index cd07d46..685671b 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -399,6 +399,8 @@
             assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor());
             assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor());
             assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor());
+            assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor());
+            assertEquals(cDay.getOnAccentTextColor(), cNight.getOnAccentTextColor());
             assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
             assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
             assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
@@ -413,20 +415,26 @@
         assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getOnAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getRippleAlpha()).isAtLeast(0x00);
         assertThat(c.getRippleAlpha()).isAtMost(0xff);
 
-        // Assert that various colors have sufficient contrast
+        // Assert that various colors have sufficient contrast with the background
         assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5);
         assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5);
 
-        // This accent color is only used for emphasized buttons
+        // These colors are only used for emphasized buttons; they do not need contrast
         assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
+        assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1);
+
+        // The text that is used within the accent color DOES need to have contrast
+        assertContrastIsAtLeast(c.getOnAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
     }
 
     private void assertContrastIsAtLeast(int foreground, int background, double minContrast) {
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
index 3d820ac..6884f13d 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
@@ -62,18 +62,4 @@
         assertThat(outDoc.getPropertyDocument("propDocument").getPropertyBytesArray("propBytes"))
                 .isEqualTo(new byte[][] {{3, 4}});
     }
-
-    @Test
-    public void testPutLargeDocument_exceedLimit() throws Exception {
-        // Create a String property that has a very large property.
-        char[] chars = new char[10_000_000];
-        String property = new StringBuilder().append(chars).append("the end.").toString();
-
-        GenericDocument doc =
-                new GenericDocument.Builder<>("namespace", "id1", "schema1")
-                        .setPropertyString("propString", property)
-                        .build();
-
-        assertThat(doc.getPropertyString("propString")).isEqualTo(property);
-    }
 }
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/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index dfc9013..149f58f 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -32,6 +32,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -121,6 +122,46 @@
         Mockito.verifyZeroInteractions(mListener);
     }
 
+    @Test
+    public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreNoOtherListeners()
+            throws RemoteException {
+        mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks();
+        Mockito.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(ALL_DISPLAY_EVENTS));
+
+        mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks();
+        Mockito.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L));
+
+    }
+
+    @Test
+    public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreListeners()
+            throws RemoteException {
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+                DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
+        InOrder inOrder = Mockito.inOrder(mDisplayManager);
+
+        inOrder.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(),
+                        eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+        mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks();
+        inOrder.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(),
+                        eq(ALL_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+        mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks();
+        inOrder.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(),
+                        eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+        mDisplayManagerGlobal.unregisterDisplayListener(mListener);
+        inOrder.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L));
+
+    }
+
     private void waitForHandler() {
         mHandler.runWithScissors(() -> { }, 0);
     }
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index fd7753b..5b3be58 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -22,6 +22,7 @@
 
 import static org.testng.Assert.assertThrows;
 
+import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
@@ -35,6 +36,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /** Tests that ensure appropriate settings are backed up. */
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -701,66 +708,67 @@
         assertThat(result.getString(KEY4, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE);
     }
 
-    // TODO(mpape): resolve b/142727848 and re-enable listener tests
-//    @Test
-//    public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
-//        final CountDownLatch countDownLatch = new CountDownLatch(1);
-//
-//        DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
-//            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-//            assertThat(properties.getKeyset()).contains(KEY);
-//            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
-//            countDownLatch.countDown();
-//        };
-//
-//        try {
-//            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
-//                    ActivityThread.currentApplication().getMainExecutor(), changeListener);
-//            DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
-//            assertThat(countDownLatch.await(
-//                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-//        } catch (InterruptedException e) {
-//            Assert.fail(e.getMessage());
-//        } finally {
-//            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
-//        }
-//    }
-//
-//    @Test
-//    public void onPropertiesChangedListener_setPropertiesCallback() throws InterruptedException {
-//        final CountDownLatch countDownLatch = new CountDownLatch(1);
-//        DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
-//        DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false);
-//
-//        Map<String, String> keyValues = new HashMap<>(2);
-//        keyValues.put(KEY, VALUE2);
-//        keyValues.put(KEY3, VALUE3);
-//        Properties setProperties = new Properties(NAMESPACE, keyValues);
-//
-//        DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
-//            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-//            assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
-//            // KEY updated from VALUE to VALUE2
-//            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2);
-//            // KEY2 deleted (returns default_value)
-//            assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value");
-//            //KEY3 added with VALUE3
-//            assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3);
-//            countDownLatch.countDown();
-//        };
-//
-//        try {
-//            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
-//                    ActivityThread.currentApplication().getMainExecutor(), changeListener);
-//            DeviceConfig.setProperties(setProperties);
-//            assertThat(countDownLatch.await(
-//                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-//        } catch (InterruptedException e) {
-//            Assert.fail(e.getMessage());
-//        } finally {
-//            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
-//        }
-//    }
+    @Test
+    public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+
+        DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
+            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+            assertThat(properties.getKeyset()).contains(KEY);
+            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
+            countDownLatch.countDown();
+        };
+
+        try {
+            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
+                    Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(),
+                    changeListener);
+            DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
+            assertThat(countDownLatch.await(
+                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+        } catch (InterruptedException e) {
+            Assert.fail(e.getMessage());
+        } finally {
+            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+        }
+    }
+
+    @Test
+    public void onPropertiesChangedListener_setPropertiesCallback() {
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
+        DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false);
+
+        Map<String, String> keyValues = new HashMap<>(2);
+        keyValues.put(KEY, VALUE2);
+        keyValues.put(KEY3, VALUE3);
+        Properties setProperties = new Properties(NAMESPACE, keyValues);
+
+        DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
+            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+            assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
+            // KEY updated from VALUE to VALUE2
+            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2);
+            // KEY2 deleted (returns default_value)
+            assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value");
+            //KEY3 added with VALUE3
+            assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3);
+            countDownLatch.countDown();
+        };
+
+        try {
+            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
+                    Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(),
+                    changeListener);
+            DeviceConfig.setProperties(setProperties);
+            assertThat(countDownLatch.await(
+                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+        } catch (InterruptedException | DeviceConfig.BadConfigException e) {
+            Assert.fail(e.getMessage());
+        } finally {
+            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+        }
+    }
 
     @Test
     public void syncDisabling() throws Exception {
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 8fd1af8..4f1da1b2 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -111,7 +111,7 @@
                 new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
                 mMockController, 10 /* durationMs */, new LinearInterpolator(),
                 0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */);
-        mController.mReadyDispatched = true;
+        mController.setReadyDispatched(true);
     }
 
     @Test
@@ -197,7 +197,7 @@
 
     @Test
     public void testCancelled_beforeReadyDispatched() {
-        mController.mReadyDispatched = false;
+        mController.setReadyDispatched(false);
         mController.cancel();
         assertFalse(mController.isReady());
         assertFalse(mController.isFinished());
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 507638e..227a8657 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -19,13 +19,17 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
 import static android.view.InsetsController.ANIMATION_TYPE_NONE;
+import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
+import static android.view.InsetsController.AnimationType;
 import static android.view.InsetsSourceConsumer.ShowResult.IME_SHOW_DELAYED;
 import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY;
+import static android.view.InsetsState.FIRST_TYPE;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.LAST_TYPE;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
@@ -662,6 +666,97 @@
     }
 
     @Test
+    public void testResizeAnimation_insetsTypes() {
+        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+            final @AnimationType int expectedAnimationType =
+                    (InsetsState.toPublicType(type) & Type.systemBars()) != 0
+                            ? ANIMATION_TYPE_RESIZE
+                            : ANIMATION_TYPE_NONE;
+            doTestResizeAnimation_insetsTypes(type, expectedAnimationType);
+        }
+    }
+
+    private void doTestResizeAnimation_insetsTypes(@InternalInsetsType int type,
+            @AnimationType int expectedAnimationType) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final InsetsState state1 = new InsetsState();
+            state1.getSource(type).setVisible(true);
+            state1.getSource(type).setFrame(0, 0, 500, 50);
+            final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+            state2.getSource(type).setFrame(0, 0, 500, 60);
+            final String message = "Animation type of " + InsetsState.typeToString(type) + ":";
+
+            // New insets source won't cause the resize animation.
+            mController.onStateChanged(state1);
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+            // Changing frame might cause the resize animation. This depends on the insets type.
+            mController.onStateChanged(state2);
+            assertEquals(message, expectedAnimationType, mController.getAnimationType(type));
+
+            // Cancel the existing animations for the next iteration.
+            mController.cancelExistingAnimations();
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testResizeAnimation_displayFrame() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final @InternalInsetsType int type = ITYPE_STATUS_BAR;
+            final InsetsState state1 = new InsetsState();
+            state1.setDisplayFrame(new Rect(0, 0, 500, 1000));
+            state1.getSource(type).setFrame(0, 0, 500, 50);
+            final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+            state2.setDisplayFrame(new Rect(0, 0, 500, 1010));
+            state2.getSource(type).setFrame(0, 0, 500, 60);
+            final String message = "There must not be resize animation.";
+
+            // New insets source won't cause the resize animation.
+            mController.onStateChanged(state1);
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+            // Changing frame won't cause the resize animation if the display frame is also changed.
+            mController.onStateChanged(state2);
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testResizeAnimation_visibility() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final @InternalInsetsType int type = ITYPE_STATUS_BAR;
+            final InsetsState state1 = new InsetsState();
+            state1.getSource(type).setVisible(true);
+            state1.getSource(type).setFrame(0, 0, 500, 50);
+            final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+            state2.getSource(type).setVisible(false);
+            state2.getSource(type).setFrame(0, 0, 500, 60);
+            final InsetsState state3 = new InsetsState(state2, true /* copySources */);
+            state3.getSource(type).setVisible(true);
+            state3.getSource(type).setFrame(0, 0, 500, 70);
+            final String message = "There must not be resize animation.";
+
+            // New insets source won't cause the resize animation.
+            mController.onStateChanged(state1);
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+            // Changing source visibility (visible --> invisible) won't cause the resize animation.
+            // The previous source and the current one must be both visible.
+            mController.onStateChanged(state2);
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+            // Changing source visibility (invisible --> visible) won't cause the resize animation.
+            // The previous source and the current one must be both visible.
+            mController.onStateChanged(state3);
+            assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
     public void testCaptionInsetsStateAssemble() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.onFrameChanged(new Rect(0, 0, 100, 300));
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 3bd2939..bf8bb76 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -216,9 +216,9 @@
         mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(0, 0, 100, 300));
         mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
 
-        Rect visibleInsets = mState.calculateVisibleInsets(
+        Insets visibleInsets = mState.calculateVisibleInsets(
                 new Rect(0, 0, 100, 400), SOFT_INPUT_ADJUST_NOTHING);
-        assertEquals(new Rect(0, 300, 0, 0), visibleInsets);
+        assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
 
     @Test
@@ -226,9 +226,9 @@
         mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(0, 0, 100, 300));
         mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
 
-        Rect visibleInsets = mState.calculateVisibleInsets(
+        Insets visibleInsets = mState.calculateVisibleInsets(
                 new Rect(0, 0, 150, 400), SOFT_INPUT_ADJUST_NOTHING);
-        assertEquals(new Rect(0, 300, 0, 0), visibleInsets);
+        assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
 
     @Test
@@ -413,9 +413,9 @@
         // Make sure bottom gestures are ignored
         mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
         mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
-        Rect visibleInsets = mState.calculateVisibleInsets(
+        Insets visibleInsets = mState.calculateVisibleInsets(
                 new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_PAN);
-        assertEquals(new Rect(0, 100, 0, 100), visibleInsets);
+        assertEquals(Insets.of(0, 100, 0, 100), visibleInsets);
     }
 
     @Test
@@ -428,9 +428,9 @@
         // Make sure bottom gestures are ignored
         mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
         mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
-        Rect visibleInsets = mState.calculateVisibleInsets(
+        Insets visibleInsets = mState.calculateVisibleInsets(
                 new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_NOTHING);
-        assertEquals(new Rect(0, 100, 0, 0), visibleInsets);
+        assertEquals(Insets.of(0, 100, 0, 0), visibleInsets);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index 623008e..98ab592 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -36,7 +36,6 @@
 @RunWith(AndroidJUnit4.class)
 public class KeyEventTest {
 
-    private static final int ID = 0xabcdef;
     private static final int DOWN_TIME = 50;
     private static final long EVENT_TIME = 100;
     private static final int ACTION = KeyEvent.ACTION_DOWN;
@@ -47,7 +46,6 @@
     private static final int SCAN_CODE = 0;
     private static final int FLAGS = 0;
     private static final int SOURCE = InputDevice.SOURCE_KEYBOARD;
-    private static final byte[] HMAC = null;
     private static final String CHARACTERS = null;
 
     private static final int ID_SOURCE_MASK = 0x3 << 30;
@@ -164,8 +162,8 @@
     }
 
     private static KeyEvent createKey() {
-        return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
-                DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
+        return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+                DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, CHARACTERS);
     }
 
     private static void compareKeys(KeyEvent key1, KeyEvent key2) {
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/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index d2b52ba..0e78f87 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -16,6 +16,12 @@
 
 package android.view.accessibility;
 
+import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_ACCESSIBILITY;
+import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_INPUT;
+import static android.view.accessibility.AccessibilityNodeInfo.ROOT_ITEM_ID;
+import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID;
+import static android.view.accessibility.AccessibilityWindowInfo.ANY_WINDOW_ID;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
@@ -597,6 +603,97 @@
     }
 
     @Test
+    public void getFocus_focusedNodeAsInitialNode_returnsNodeWithA11yFocus() {
+        AccessibilityNodeInfo nodeInfo = addFocusedNode(FOCUS_ACCESSIBILITY);
+        assertFocus(nodeInfo, FOCUS_ACCESSIBILITY, nodeInfo.getSourceNodeId(),
+                nodeInfo.getWindowId());
+    }
+
+    @Test
+    public void getFocus_focusedNodeAsInitialNode_returnsNodeWithInputFocus() {
+        AccessibilityNodeInfo nodeInfo = addFocusedNode(FOCUS_INPUT);
+        assertFocus(nodeInfo, FOCUS_INPUT, nodeInfo.getSourceNodeId(), nodeInfo.getWindowId());
+    }
+
+
+    @Test
+    public void getFocus_fromAnyWindow_returnsNodeWithA11yFocus() {
+        AccessibilityNodeInfo parentNodeInfo =
+                getNodeWithA11yAndWindowId(ROOT_ITEM_ID, WINDOW_ID_1);
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setParent(getMockViewWithA11yAndWindowIds(ROOT_ITEM_ID, WINDOW_ID_1));
+        setFocus(nodeInfo, FOCUS_ACCESSIBILITY);
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(nodeInfo);
+
+        AccessibilityNodeInfo focusedNodeInfo =
+                mAccessibilityCache.getFocus(FOCUS_ACCESSIBILITY, ROOT_NODE_ID, ANY_WINDOW_ID);
+        try {
+            assertEquals(focusedNodeInfo, nodeInfo);
+        } finally {
+            nodeInfo.recycle();
+            parentNodeInfo.recycle();
+        }
+    }
+
+    @Test
+    public void getFocus_fromAnyWindow_returnsNodeWithInputFocus() {
+        AccessibilityNodeInfo parentNodeInfo =
+                getNodeWithA11yAndWindowId(ROOT_ITEM_ID, WINDOW_ID_1);
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setParent(getMockViewWithA11yAndWindowIds(ROOT_ITEM_ID, WINDOW_ID_1));
+        setFocus(nodeInfo, FOCUS_INPUT);
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(nodeInfo);
+
+        AccessibilityNodeInfo focusedNodeInfo =
+                mAccessibilityCache.getFocus(FOCUS_INPUT, ROOT_NODE_ID, ANY_WINDOW_ID);
+        try {
+            assertEquals(focusedNodeInfo, nodeInfo);
+        } finally {
+            nodeInfo.recycle();
+            parentNodeInfo.recycle();
+        }
+    }
+
+
+    @Test
+    public void getFocus_parentNodeAsInitialNode_returnsNodeWithA11yFocus() {
+        findFocusReturnsFocus_initialNodeIsParent(FOCUS_ACCESSIBILITY);
+    }
+
+    @Test
+    public void getFocus_parentNodeAsInitialNode_returnsNodeWithInputFocus() {
+        findFocusReturnsFocus_initialNodeIsParent(FOCUS_INPUT);
+
+    }
+
+    @Test
+    public void getFocus_nonFocusedChildNodeAsInitialNode_returnsNullA11yFocus() {
+        findFocusReturnNull_initialNodeIsNotFocusOrFocusAncestor(FOCUS_ACCESSIBILITY);
+    }
+
+    @Test
+    public void getFocus_nonFocusedChildNodeAsInitialNode_returnsNullInputFocus() {
+        findFocusReturnNull_initialNodeIsNotFocusOrFocusAncestor(FOCUS_INPUT);
+    }
+
+    @Test
+    public void getFocus_cacheCleared_returnsNullA11yFocus() {
+        AccessibilityNodeInfo nodeInfo = addFocusedNode(FOCUS_ACCESSIBILITY);
+        mAccessibilityCache.clear();
+        assertFocus(null, FOCUS_ACCESSIBILITY, nodeInfo.getSourceNodeId(),
+                nodeInfo.getWindowId());
+    }
+
+    @Test
+    public void getFocus_cacheCleared_returnsNullInputFocus() {
+        AccessibilityNodeInfo nodeInfo = addFocusedNode(FOCUS_INPUT);
+        mAccessibilityCache.clear();
+        assertFocus(null, FOCUS_INPUT, nodeInfo.getSourceNodeId(), nodeInfo.getWindowId());
+    }
+
+    @Test
     public void nodeSourceOfInputFocusEvent_getsRefreshed() {
         AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
         nodeInfo.setFocused(false);
@@ -786,6 +883,86 @@
         }
     }
 
+    private AccessibilityNodeInfo addFocusedNode(int focusType) {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        setFocus(nodeInfo, focusType);
+        mAccessibilityCache.add(nodeInfo);
+        return nodeInfo;
+    }
+
+    private void assertFocus(AccessibilityNodeInfo focus, int focusType, long nodeId,
+            int windowId) {
+        AccessibilityNodeInfo focusedNodeInfo = mAccessibilityCache.getFocus(
+                focusType, nodeId, windowId);
+        try {
+            assertEquals(focusedNodeInfo, focus);
+        } finally {
+            if (focus != null) {
+                focus.recycle();
+            }
+            if (focusedNodeInfo != null) {
+                focusedNodeInfo.recycle();
+            }
+        }
+    }
+
+
+    private void findFocusReturnNull_initialNodeIsNotFocusOrFocusAncestor(int focusType) {
+        AccessibilityNodeInfo parentNodeInfo =
+                getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1);
+        AccessibilityNodeInfo childNodeInfo =
+                getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1);
+        AccessibilityNodeInfo otherChildNodeInfo =
+                getNodeWithA11yAndWindowId(OTHER_CHILD_VIEW_ID, WINDOW_ID_1);
+        childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+        otherChildNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+        setFocus(childNodeInfo, focusType);
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(childNodeInfo);
+        mAccessibilityCache.add(otherChildNodeInfo);
+
+        AccessibilityNodeInfo focusedNodeInfo = mAccessibilityCache.getFocus(
+                focusType, otherChildNodeInfo.getSourceNodeId(), WINDOW_ID_1);
+
+        try {
+            assertNull(focusedNodeInfo);
+
+        } finally {
+            parentNodeInfo.recycle();
+            childNodeInfo.recycle();
+        }
+    }
+
+    private void findFocusReturnsFocus_initialNodeIsParent(int focusType) {
+        AccessibilityNodeInfo parentNodeInfo =
+                getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1);
+        AccessibilityNodeInfo childNodeInfo =
+                getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1);
+        childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+        setFocus(childNodeInfo, focusType);
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(childNodeInfo);
+
+        AccessibilityNodeInfo focusedNodeInfo = mAccessibilityCache.getFocus(
+                focusType, parentNodeInfo.getSourceNodeId(), WINDOW_ID_1);
+
+        try {
+            assertEquals(focusedNodeInfo, childNodeInfo);
+
+        } finally {
+            parentNodeInfo.recycle();
+            childNodeInfo.recycle();
+        }
+    }
+
+    private void setFocus(AccessibilityNodeInfo info, int focusType) {
+        if (focusType == FOCUS_ACCESSIBILITY) {
+            info.setAccessibilityFocused(true);
+        } else {
+            info.setFocused(true);
+        }
+    }
+
     private AccessibilityWindowInfo obtainAccessibilityWindowInfo(int windowId, int layer) {
         AccessibilityWindowInfo windowInfo = AccessibilityWindowInfo.obtain();
         windowInfo.setId(windowId);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 6e34a33..cfcbc7d 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -269,7 +269,7 @@
         onView(withId(R.id.content_preview_thumbnail)).check(matches(isDisplayed()));
     }
 
-    @Test
+    @Test @Ignore
     public void twoOptionsAndUserSelectsOne() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -298,7 +298,7 @@
         assertThat(chosen[0], is(toChoose));
     }
 
-    @Test
+    @Test @Ignore
     public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
 
@@ -351,7 +351,7 @@
         }
     }
 
-    @Test
+    @Test @Ignore
     public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -424,7 +424,7 @@
         assertThat(activity.isFinishing(), is(true));
     }
 
-    @Test
+    @Test @Ignore
     public void hasOtherProfileOneOption() throws Exception {
         // enable the work tab feature flag
         ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -461,7 +461,7 @@
         assertThat(chosen[0], is(toChoose));
     }
 
-    @Test
+    @Test @Ignore
     public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
         // enable the work tab feature flag
         ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -500,7 +500,7 @@
         assertThat(chosen[0], is(toChoose));
     }
 
-    @Test
+    @Test @Ignore
     public void hasLastChosenActivityAndOtherProfile() throws Exception {
         // enable the work tab feature flag
         ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -564,7 +564,7 @@
         assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK);
     }
 
-    @Test
+    @Test @Ignore
     public void copyTextToClipboardLogging() throws Exception {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -595,7 +595,7 @@
     }
 
 
-    @Test
+    @Test @Ignore
     public void testNearbyShareLogging() throws Exception {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -643,7 +643,7 @@
 
 
 
-    @Test
+    @Test @Ignore
     public void testEditImageLogs() throws Exception {
         Intent sendIntent = createSendImageIntent(
                 Uri.parse("android.resource://com.android.frameworks.coretests/"
@@ -1129,7 +1129,7 @@
     }
 
     // This test is too long and too slow and should not be taken as an example for future tests.
-    @Test
+    @Test @Ignore
     public void testDirectTargetSelectionLogging() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         // We need app targets for direct targets to get displayed
@@ -1162,8 +1162,7 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos,
-                        List.of())
+                        directShareToShortcutInfos)
         );
 
         // Thread.sleep shouldn't be a thing in an integration test but it's
@@ -1200,7 +1199,7 @@
     }
 
     // This test is too long and too slow and should not be taken as an example for future tests.
-    @Test
+    @Test @Ignore
     public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         // We need app targets for direct targets to get displayed
@@ -1234,8 +1233,7 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos,
-                        List.of())
+                        directShareToShortcutInfos)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
@@ -1266,7 +1264,7 @@
                 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
     }
 
-    @Test
+    @Test @Ignore
     public void testShortcutTargetWithApplyAppLimits() throws InterruptedException {
         // Set up resources
         sOverrides.resources = Mockito.spy(
@@ -1305,8 +1303,7 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
-                        directShareToShortcutInfos,
-                        List.of())
+                        directShareToShortcutInfos)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
@@ -1323,7 +1320,7 @@
                 activity.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0"));
     }
 
-    @Test
+    @Test @Ignore
     public void testShortcutTargetWithoutApplyAppLimits() throws InterruptedException {
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
@@ -1366,8 +1363,7 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
-                        directShareToShortcutInfos,
-                        List.of())
+                        directShareToShortcutInfos)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
@@ -1387,13 +1383,13 @@
     }
 
     // This test is too long and too slow and should not be taken as an example for future tests.
-    @Test
+    @Test @Ignore
     public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
             throws InterruptedException {
         testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4);
     }
 
-    @Test
+    @Test @Ignore
     public void testDirectTargetLoggingWithAppTargetNotRankedLandscape()
             throws InterruptedException {
         testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8);
@@ -1442,8 +1438,7 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos,
-                        List.of())
+                        directShareToShortcutInfos)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
@@ -1554,7 +1549,7 @@
         assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
     }
 
-    @Test
+    @Test @Ignore
     public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
         // enable the work tab feature flag
         ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -1719,7 +1714,7 @@
                 .check(matches(isDisplayed()));
     }
 
-    @Test
+    @Test @Ignore
     public void testAppTargetLogging() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1775,7 +1770,7 @@
                         .SharesheetTargetSelectedEvent.SHARESHEET_APP_TARGET_SELECTED.getId()));
     }
 
-    @Test
+    @Test @Ignore
     public void testDirectTargetLogging() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         // We need app targets for direct targets to get displayed
@@ -1806,8 +1801,7 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos,
-                        null)
+                        directShareToShortcutInfos)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
@@ -1856,7 +1850,7 @@
                         .SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId()));
     }
 
-    @Test
+    @Test @Ignore
     public void testEmptyDirectRowLogging() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
         // We need app targets for direct targets to get displayed
@@ -1907,7 +1901,7 @@
                         .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
     }
 
-    @Test
+    @Test @Ignore
     public void testCopyTextToClipboardLogging() throws Exception {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1953,7 +1947,7 @@
                         .SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId()));
     }
 
-    @Test
+    @Test @Ignore
     public void testSwitchProfileLogging() throws InterruptedException {
         // enable the work tab feature flag
         ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -2249,12 +2243,6 @@
                     (chooserListAdapter.getUserHandle().getIdentifier() == 10);
             return null;
         };
-        boolean[] isQueryTargetServicesCalledOnWorkProfile = new boolean[] { false };
-        sOverrides.onQueryTargetServices = chooserListAdapter -> {
-            isQueryTargetServicesCalledOnWorkProfile[0] =
-                    (chooserListAdapter.getUserHandle().getIdentifier() == 10);
-            return null;
-        };
         Intent sendIntent = createSendTextIntent();
         sendIntent.setType("TestType");
 
@@ -2267,8 +2255,6 @@
 
         assertFalse("Direct share targets were queried on a paused work profile",
                 isQueryDirectShareCalledOnWorkProfile[0]);
-        assertFalse("Target services were queried on a paused work profile",
-                isQueryTargetServicesCalledOnWorkProfile[0]);
     }
 
     @Test
@@ -2288,12 +2274,6 @@
                     (chooserListAdapter.getUserHandle().getIdentifier() == 10);
             return null;
         };
-        boolean[] isQueryTargetServicesCalledOnWorkProfile = new boolean[] { false };
-        sOverrides.onQueryTargetServices = chooserListAdapter -> {
-            isQueryTargetServicesCalledOnWorkProfile[0] =
-                    (chooserListAdapter.getUserHandle().getIdentifier() == 10);
-            return null;
-        };
         Intent sendIntent = createSendTextIntent();
         sendIntent.setType("TestType");
 
@@ -2306,8 +2286,6 @@
 
         assertFalse("Direct share targets were queried on a locked work profile user",
                 isQueryDirectShareCalledOnWorkProfile[0]);
-        assertFalse("Target services were queried on a locked work profile user",
-                isQueryTargetServicesCalledOnWorkProfile[0]);
     }
 
     @Test
@@ -2352,12 +2330,6 @@
                     (chooserListAdapter.getUserHandle().getIdentifier() == 10);
             return null;
         };
-        boolean[] isQueryTargetServicesCalledOnWorkProfile = new boolean[] { false };
-        sOverrides.onQueryTargetServices = chooserListAdapter -> {
-            isQueryTargetServicesCalledOnWorkProfile[0] =
-                    (chooserListAdapter.getUserHandle().getIdentifier() == 10);
-            return null;
-        };
         Intent sendIntent = createSendTextIntent();
         sendIntent.setType("TestType");
 
@@ -2370,8 +2342,6 @@
 
         assertFalse("Direct share targets were queried on a locked work profile user",
                 isQueryDirectShareCalledOnWorkProfile[0]);
-        assertFalse("Target services were queried on a locked work profile user",
-                isQueryTargetServicesCalledOnWorkProfile[0]);
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 9fcab09..6b3d657 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -229,14 +229,6 @@
     }
 
     @Override
-    protected void queryTargetServices(ChooserListAdapter adapter) {
-        if (sOverrides.onQueryTargetServices != null) {
-            sOverrides.onQueryTargetServices.apply(adapter);
-        }
-        super.queryTargetServices(adapter);
-    }
-
-    @Override
     protected boolean isQuietModeEnabled(UserHandle userHandle) {
         return sOverrides.isQuietModeEnabled;
     }
@@ -267,7 +259,6 @@
         public Function<PackageManager, PackageManager> createPackageManager;
         public Function<TargetInfo, Boolean> onSafelyStartCallback;
         public Function<ChooserListAdapter, Void> onQueryDirectShareTargets;
-        public Function<ChooserListAdapter, Void> onQueryTargetServices;
         public ResolverListController resolverListController;
         public ResolverListController workResolverListController;
         public Boolean isVoiceInteraction;
@@ -290,7 +281,6 @@
         public void reset() {
             onSafelyStartCallback = null;
             onQueryDirectShareTargets = null;
-            onQueryTargetServices = null;
             isVoiceInteraction = null;
             createPackageManager = null;
             previewThumbnail = null;
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt b/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
new file mode 100644
index 0000000..8355daa
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
@@ -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.internal.inputmethod
+
+import android.annotation.DurationMillisLong
+import android.os.Handler
+import android.os.SystemClock
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicLong
+import java.util.concurrent.atomic.AtomicReference
+
+@DurationMillisLong
+const val SHORT_PERIOD_MILLI = 50L
+const val SHORT_PERIOD_NANO = SHORT_PERIOD_MILLI * 1_000_000L
+
+@DurationMillisLong
+const val TIMEOUT_MILLI = 10_000L
+const val TIMEOUT_NANO = TIMEOUT_MILLI * 1_000_000L
+
+const val ERROR_MESSAGE = "Test Error Message!"
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class CompletableFutureUtilTest {
+
+    private inline fun assertRuntimeException(expectedMessage: String, block: () -> Unit) {
+        try {
+            block()
+            fail()
+        } catch (exception: RuntimeException) {
+            assertThat(exception.message).isEqualTo(expectedMessage)
+            // Expected
+        } catch (exception: Throwable) {
+            fail("RuntimeException is expected but got $exception")
+        }
+    }
+
+    private inline fun runOnMainDelayed(delay: Long, crossinline block: () -> Unit) {
+        val handler = Handler.createAsync(
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getMainLooper())
+        handler.postDelayed({
+            block()
+        }, delay)
+    }
+
+    @Test
+    fun testCharSequenceTimedOut() {
+        val completable = CompletableFuture<CharSequence>()
+
+        assertThat(completable.isDone).isFalse()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, null, SHORT_PERIOD_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(completable.isDone).isFalse()
+        assertThat(result).isNull()
+        assertThat(elapsed).isGreaterThan(SHORT_PERIOD_NANO)
+    }
+
+    @Test
+    fun testCharSequenceTimedOutWithInterruption() {
+        val completable = CompletableFuture<CharSequence>()
+
+        val beginNanosRef = AtomicLong()
+        val endNanosRef = AtomicLong()
+        val isInterruptedRef = AtomicBoolean()
+        val resultRef = AtomicReference<CharSequence>()
+
+        // Verifies that calling getResultOrNull() on an interrupted thread still times out with
+        // preserving the interrupted state.
+        val thread = Thread {
+            val currentThread = Thread.currentThread()
+            currentThread.interrupt()
+            beginNanosRef.set(SystemClock.elapsedRealtimeNanos())
+            resultRef.set(CompletableFutureUtil.getResultOrNull(
+                    completable, null, null, null, SHORT_PERIOD_MILLI))
+            endNanosRef.set(SystemClock.elapsedRealtimeNanos())
+            isInterruptedRef.set(currentThread.isInterrupted())
+        }
+
+        thread.run()
+        thread.join(TIMEOUT_MILLI)
+        assertThat(thread.isAlive).isFalse()
+
+        val elapsedTime = endNanosRef.get() - beginNanosRef.get()
+        assertThat(elapsedTime).isGreaterThan(SHORT_PERIOD_NANO)
+        assertThat(resultRef.get()).isNull()
+        assertThat(isInterruptedRef.get()).isTrue()
+    }
+
+    @Test
+    fun testCharSequenceAfterCompletion() {
+        val expectedValue = "Expected Value"
+        val completable = CompletableFuture<CharSequence>()
+
+        assertThat(completable.isDone).isFalse()
+        completable.complete(expectedValue)
+        assertThat(completable.isDone).isTrue()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, null,
+                TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(result).isEqualTo(expectedValue)
+        assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+    }
+
+    @Test
+    fun testCharSequenceAfterError() {
+        val completable = CompletableFuture<CharSequence>()
+
+        assertThat(completable.isDone).isFalse()
+        completable.completeExceptionally(UnsupportedOperationException(ERROR_MESSAGE))
+        assertThat(completable.isDone).isTrue()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, null, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(result).isNull()
+        assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+
+        assertRuntimeException(ERROR_MESSAGE) {
+            CompletableFutureUtil.getResult(completable)
+        }
+    }
+
+    @Test
+    fun testCharSequenceAfterCancellation() {
+        val completable = CompletableFuture<CharSequence>()
+        val cancellationGroup = CancellationGroup()
+        cancellationGroup.cancelAll()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        // due to the side-effect of cancellationGroup, the object is already completed here.
+        assertThat(completable.isDone).isTrue()
+        assertThat(result).isNull()
+        assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+
+        // as the object is already cancelled due to the side-effect of cancellationGroup, it cannot
+        // accept a result any more.
+        completable.complete("Hello!")
+        assertThat(completable.isCancelled).isTrue()
+    }
+
+    @Test
+    fun testCharSequenceAfterCompleteAndCancellation() {
+        val expectedValue = "Expected Value"
+        val completable = CompletableFuture<CharSequence>()
+        completable.complete(expectedValue)
+
+        val cancellationGroup = CancellationGroup()
+        cancellationGroup.cancelAll()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(result).isEqualTo(expectedValue)
+        assertThat(CompletableFutureUtil.getResult(completable)).isEqualTo(expectedValue)
+        assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+    }
+
+    @Test
+    fun testCharSequenceMultipleAssignment() {
+        val expectedValue = "Expected Value"
+        val notExpectedValue = "Not Expected Value"
+        val completable = CompletableFuture<CharSequence>()
+        completable.complete(expectedValue)
+        completable.complete(notExpectedValue)
+        assertThat(completable.isDone).isTrue()
+
+        assertThat(CompletableFutureUtil.getResult(completable)).isEqualTo(expectedValue)
+    }
+
+    @Test
+    fun testCharSequenceUnblockByCompletion() {
+        val expectedValue = "Expected Value"
+        val completable = CompletableFuture<CharSequence>()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        runOnMainDelayed(SHORT_PERIOD_MILLI) {
+            completable.complete(expectedValue)
+        }
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, null, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(completable.isDone).isTrue()
+        assertThat(result).isEqualTo(expectedValue)
+        assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+    }
+
+    @Test
+    fun testCharSequenceUnblockByCompletionWithCancellationGroup() {
+        val expectedValue = "Expected Value"
+        val completable = CompletableFuture<CharSequence>()
+        var cancellationGroup = CancellationGroup()
+
+        assertThat(cancellationGroup.isCanceled).isFalse()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        runOnMainDelayed(SHORT_PERIOD_MILLI) {
+            completable.complete(expectedValue)
+        }
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(cancellationGroup.isCanceled).isFalse()
+        assertThat(completable.isDone).isTrue()
+        assertThat(result).isEqualTo(expectedValue)
+        assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+    }
+
+    @Test
+    fun testCharSequenceUnblockByError() {
+        val completable = CompletableFuture<CharSequence>()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        runOnMainDelayed(SHORT_PERIOD_MILLI) {
+            completable.completeExceptionally(UnsupportedOperationException(ERROR_MESSAGE))
+        }
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, null, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        assertThat(completable.isDone).isTrue()
+        assertThat(result).isNull()
+        assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+    }
+
+    @Test
+    fun testCharSequenceUnblockByCancellation() {
+        val completable = CompletableFuture<CharSequence>()
+        val cancellationGroup = CancellationGroup()
+
+        val beginNanos = SystemClock.elapsedRealtimeNanos()
+        runOnMainDelayed(SHORT_PERIOD_MILLI) {
+            cancellationGroup.cancelAll()
+        }
+        val result = CompletableFutureUtil.getResultOrNull(
+                completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+        val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+        // due to the side-effect of cancellationGroup.
+        assertThat(completable.isDone).isTrue()
+        assertThat(result).isNull()
+        assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+    }
+}
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 cb6e88b..e8e4330 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -23,6 +23,8 @@
 import android.os.BatteryStats;
 import android.os.BatteryStats.HistoryItem;
 import android.os.BatteryStats.Uid.Sensor;
+import android.os.Process;
+import android.os.UserHandle;
 import android.os.WorkSource;
 import android.util.SparseLongArray;
 import android.view.Display;
@@ -53,6 +55,8 @@
 public class BatteryStatsNoteTest extends TestCase {
 
     private static final int UID = 10500;
+    private static final int ISOLATED_APP_ID = Process.FIRST_ISOLATED_UID + 23;
+    private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID);
     private static final WorkSource WS = new WorkSource(UID);
 
     /**
@@ -114,6 +118,88 @@
         assertEquals(120_000, bgTime);
     }
 
+    /**
+     * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid.
+     */
+    @SmallTest
+    public void testNoteStartWakeLocked_isolatedUid() throws Exception {
+        final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+        int pid = 10;
+        String name = "name";
+        String historyName = "historyName";
+
+        WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain();
+        isolatedWorkChain.addNode(ISOLATED_UID, name);
+
+        // Map ISOLATED_UID to UID.
+        bi.addIsolatedUidLocked(ISOLATED_UID, UID);
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+        bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+                WAKE_TYPE_PARTIAL, false);
+
+        clocks.realtime = clocks.uptime = 100;
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+        clocks.realtime = clocks.uptime = 220;
+        bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+                WAKE_TYPE_PARTIAL);
+
+        // ISOLATED_UID wakelock time should be attributed to UID.
+        BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID)
+                .getAggregatedPartialWakelockTimer();
+        long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+        long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+        assertEquals(220_000, actualTime);
+        assertEquals(120_000, bgTime);
+    }
+
+    /**
+     * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid, with a race where the
+     * isolated uid is removed from batterystats before the wakelock has been stopped.
+     */
+    @SmallTest
+    public void testNoteStartWakeLocked_isolatedUidRace() throws Exception {
+        final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+        int pid = 10;
+        String name = "name";
+        String historyName = "historyName";
+
+        WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain();
+        isolatedWorkChain.addNode(ISOLATED_UID, name);
+
+        // Map ISOLATED_UID to UID.
+        bi.addIsolatedUidLocked(ISOLATED_UID, UID);
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+        bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+                WAKE_TYPE_PARTIAL, false);
+
+        clocks.realtime = clocks.uptime = 100;
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+        clocks.realtime = clocks.uptime = 150;
+        bi.maybeRemoveIsolatedUidLocked(ISOLATED_UID, clocks.realtime, clocks.uptime);
+
+        clocks.realtime = clocks.uptime = 220;
+        bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+                WAKE_TYPE_PARTIAL);
+
+        // ISOLATED_UID wakelock time should be attributed to UID.
+        BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID)
+                .getAggregatedPartialWakelockTimer();
+        long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+        long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+        assertEquals(220_000, actualTime);
+        assertEquals(120_000, bgTime);
+    }
+
 
     /**
      * Test BatteryStatsImpl.noteUidProcessStateLocked.
@@ -504,7 +590,7 @@
     public void testUpdateDisplayMeasuredEnergyStatsLocked() {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
-        bi.initMeasuredEnergyStats();
+        bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
 
         clocks.realtime = 0;
         int screen = Display.STATE_OFF;
@@ -589,7 +675,7 @@
     public void testUpdateCustomMeasuredEnergyStatsLocked_neverCalled() {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
-        bi.initMeasuredEnergyStats();
+        bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
         bi.setOnBatteryInternal(true);
 
         final int uid1 = 11500;
@@ -603,7 +689,7 @@
     public void testUpdateCustomMeasuredEnergyStatsLocked() {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
-        bi.initMeasuredEnergyStats();
+        bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
 
         final int bucketA = 0; // Custom bucket 0
         final int bucketB = 1; // Custom bucket 1
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index 0147cdb..74b6dbe 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -18,6 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.BatteryConsumer;
@@ -263,6 +266,39 @@
                 .of(180.0);
     }
 
+    @Test
+    public void testAggregateBatteryStats_incompatibleSnapshot() {
+        Context context = InstrumentationRegistry.getContext();
+        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+        batteryStats.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
+
+        BatteryUsageStatsStore batteryUsageStatsStore = mock(BatteryUsageStatsStore.class);
+
+        when(batteryUsageStatsStore.listBatteryUsageStatsTimestamps())
+                .thenReturn(new long[]{1000, 2000});
+
+        when(batteryUsageStatsStore.loadBatteryUsageStats(1000)).thenReturn(
+                new BatteryUsageStats.Builder(batteryStats.getCustomEnergyConsumerNames())
+                        .setStatsDuration(1234).build());
+
+        // Add a snapshot, with a different set of custom power components.  It should
+        // be skipped by the aggregation.
+        when(batteryUsageStatsStore.loadBatteryUsageStats(2000)).thenReturn(
+                new BatteryUsageStats.Builder(new String[]{"different"})
+                        .setStatsDuration(4321).build());
+
+        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context,
+                batteryStats, batteryUsageStatsStore);
+
+        BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
+                .aggregateSnapshots(0, 3000)
+                .build();
+        final BatteryUsageStats stats = provider.getBatteryUsageStats(query);
+        assertThat(stats.getCustomPowerComponentNames())
+                .isEqualTo(batteryStats.getCustomEnergyConsumerNames());
+        assertThat(stats.getStatsDuration()).isEqualTo(1234);
+    }
+
     private static class TestHandler extends Handler {
         TestHandler() {
             super(Looper.getMainLooper());
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
new file mode 100644
index 0000000..26296f1
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -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.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LongArrayMultiStateCounterTest {
+
+    @Test
+    public void setStateAndUpdateValue() {
+        LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
+                new LongArrayMultiStateCounter.LongArrayContainer(4);
+        LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
+        counter.setState(1, 2000);
+        counter.setState(0, 4000);
+        longArrayContainer.setValues(new long[]{100, 200, 300, 400});
+        counter.updateValues(longArrayContainer, 9000);
+        counter.getCounts(longArrayContainer, 0);
+
+        long[] result = new long[4];
+        longArrayContainer.getValues(result);
+        assertThat(result).isEqualTo(new long[]{75, 150, 225, 300});
+
+        counter.getCounts(longArrayContainer, 1);
+        longArrayContainer.getValues(result);
+        assertThat(result).isEqualTo(new long[]{25, 50, 75, 100});
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index c8387cb..d57eb65a 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -57,11 +57,10 @@
         this(new MockClock());
     }
 
-    public void initMeasuredEnergyStats() {
+    public void initMeasuredEnergyStats(String[] customBucketNames) {
         final boolean[] supportedStandardBuckets =
                 new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
         Arrays.fill(supportedStandardBuckets, true);
-        final String[] customBucketNames = {"FOO", "BAR"};
         mGlobalMeasuredEnergyStats =
                 new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
     }
diff --git a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
new file mode 100644
index 0000000..9da720c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * 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.util;
+
+import static androidx.core.graphics.ColorUtils.calculateContrast;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Color;
+
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+public class ContrastColorUtilTest extends TestCase {
+
+    @SmallTest
+    public void testEnsureTextContrastAgainstDark() {
+        int darkBg = 0xFF35302A;
+
+        int blueContrastColor = ContrastColorUtil.ensureTextContrast(Color.BLUE, darkBg, true);
+        assertContrastIsWithinRange(blueContrastColor, darkBg, 4.5, 4.75);
+
+        int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, darkBg, true);
+        assertContrastIsWithinRange(redContrastColor, darkBg, 4.5, 4.75);
+
+        final int darkGreen = 0xff008800;
+        int greenContrastColor = ContrastColorUtil.ensureTextContrast(darkGreen, darkBg, true);
+        assertContrastIsWithinRange(greenContrastColor, darkBg, 4.5, 4.75);
+
+        int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.DKGRAY, darkBg, true);
+        assertContrastIsWithinRange(grayContrastColor, darkBg, 4.5, 4.75);
+
+        int selfContrastColor = ContrastColorUtil.ensureTextContrast(darkBg, darkBg, true);
+        assertContrastIsWithinRange(selfContrastColor, darkBg, 4.5, 4.75);
+    }
+
+    @SmallTest
+    public void testEnsureTextContrastAgainstLight() {
+        int lightBg = 0xFFFFF8F2;
+
+        final int lightBlue = 0xff8888ff;
+        int blueContrastColor = ContrastColorUtil.ensureTextContrast(lightBlue, lightBg, false);
+        assertContrastIsWithinRange(blueContrastColor, lightBg, 4.5, 4.75);
+
+        int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, lightBg, false);
+        assertContrastIsWithinRange(redContrastColor, lightBg, 4.5, 4.75);
+
+        int greenContrastColor = ContrastColorUtil.ensureTextContrast(Color.GREEN, lightBg, false);
+        assertContrastIsWithinRange(greenContrastColor, lightBg, 4.5, 4.75);
+
+        int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.LTGRAY, lightBg, false);
+        assertContrastIsWithinRange(grayContrastColor, lightBg, 4.5, 4.75);
+
+        int selfContrastColor = ContrastColorUtil.ensureTextContrast(lightBg, lightBg, false);
+        assertContrastIsWithinRange(selfContrastColor, lightBg, 4.5, 4.75);
+    }
+
+    private void assertContrastIsWithinRange(int foreground, int background,
+            double minContrast, double maxContrast) {
+        assertContrastIsAtLeast(foreground, background, minContrast);
+        assertContrastIsAtMost(foreground, background, maxContrast);
+    }
+
+    private void assertContrastIsAtLeast(int foreground, int background, double minContrast) {
+        try {
+            assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast);
+        } catch (AssertionError e) {
+            throw new AssertionError(
+                    String.format("Insufficient contrast: foreground=#%08x background=#%08x",
+                            foreground, background), e);
+        }
+    }
+
+    private void assertContrastIsAtMost(int foreground, int background, double maxContrast) {
+        try {
+            assertThat(calculateContrast(foreground, background)).isAtMost(maxContrast);
+        } catch (AssertionError e) {
+            throw new AssertionError(
+                    String.format("Excessive contrast: foreground=#%08x background=#%08x",
+                            foreground, background), e);
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/OWNERS b/core/tests/coretests/src/com/android/internal/util/OWNERS
new file mode 100644
index 0000000..d832745
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/OWNERS
@@ -0,0 +1,2 @@
+per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
\ No newline at end of file
diff --git a/core/tests/mockingcoretests/src/android/window/SizeConfigurationBucketsTest.java b/core/tests/mockingcoretests/src/android/window/SizeConfigurationBucketsTest.java
new file mode 100644
index 0000000..fa4aa80
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/window/SizeConfigurationBucketsTest.java
@@ -0,0 +1,379 @@
+/*
+ * 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.window;
+
+import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.res.Configuration.SCREENLAYOUT_COMPAT_NEEDED;
+import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
+import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_RTL;
+import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_UNDEFINED;
+import static android.content.res.Configuration.SCREENLAYOUT_LONG_NO;
+import static android.content.res.Configuration.SCREENLAYOUT_LONG_YES;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_UNDEFINED;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_NORMAL;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_SMALL;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.res.Configuration;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * Tests for {@link SizeConfigurationBuckets}
+ *
+ * Build/Install/Run:
+ *  atest FrameworksMockingCoreTests:SizeConfigurationBucketsTest
+ */
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SizeConfigurationBucketsTest {
+
+    /**
+     * Tests that a change in any of the non-size-related screen layout fields results in
+     * {@link SizeConfigurationBuckets#areNonSizeLayoutFieldsUnchanged} returning false.
+     */
+    @Test
+    public void testNonSizeRelatedScreenLayoutFields() {
+        // Test layout direction
+        assertEquals(true, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_LAYOUTDIR_UNDEFINED));
+        assertEquals(false, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_LAYOUTDIR_LTR));
+        assertEquals(false, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_LAYOUTDIR_RTL));
+
+        // Test layout roundness
+        assertEquals(true, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_ROUND_UNDEFINED));
+        assertEquals(false, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_ROUND_NO));
+        assertEquals(false, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_ROUND_YES));
+
+        // Test layout compat needed
+        assertEquals(false, SizeConfigurationBuckets
+                .areNonSizeLayoutFieldsUnchanged(0, SCREENLAYOUT_COMPAT_NEEDED));
+    }
+
+    /**
+     * Tests that null size configuration buckets unflips the correct configuration flags.
+     */
+    @Test
+    public void testNullSizeConfigurationBuckets() {
+        // Check that all 3 size configurations are filtered out of the diff if the buckets are null
+        // and non-size attributes of screen layout are unchanged. Add a non-size related config
+        // change (i.e. CONFIG_LOCALE) to test that the diff is not set to zero.
+        final int diff = CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_SCREEN_LAYOUT
+                | CONFIG_LOCALE;
+        final int filteredDiffNonSizeLayoutUnchanged = SizeConfigurationBuckets.filterDiff(diff,
+                Configuration.EMPTY, Configuration.EMPTY, null);
+        assertEquals(CONFIG_LOCALE, filteredDiffNonSizeLayoutUnchanged);
+
+        // Check that only screen size and smallest screen size are filtered out of the diff if the
+        // buckets are null and non-size attributes of screen layout are changed.
+        final Configuration newConfig = new Configuration();
+        newConfig.screenLayout |= SCREENLAYOUT_ROUND_YES;
+        final int filteredDiffNonSizeLayoutChanged = SizeConfigurationBuckets.filterDiff(diff,
+                Configuration.EMPTY, newConfig, null);
+        assertEquals(CONFIG_SCREEN_LAYOUT | CONFIG_LOCALE, filteredDiffNonSizeLayoutChanged);
+    }
+
+    /**
+     * Tests that {@link SizeConfigurationBuckets.crossesSizeThreshold()} correctly checks whether
+     * the bucket thresholds have or have not been crossed. This test includes boundary checks
+     * to ensure that arithmetic is inclusive and exclusive in the right places.
+     */
+    @Test
+    public void testCrossesSizeThreshold() {
+        final int[] thresholds = new int[] { 360, 600 };
+        final int nThresholds = thresholds.length;
+        for (int i = -1; i < nThresholds; i++) {
+            final int minValueInBucket = i < 0 ? 0 : thresholds[i];
+            final int maxValueInBucket = i < nThresholds - 1
+                    ? thresholds[i + 1] - 1 : Integer.MAX_VALUE;
+            final int bucketRange = maxValueInBucket - minValueInBucket;
+            // Set old value to 1/4 in between the two thresholds.
+            final int oldValue = (int) (minValueInBucket + bucketRange * 0.25);
+            // Test 3 values of new value spread across bucket range: minValueInBucket, bucket
+            // midpoint, and max value in bucket. In all 3 cases, the bucket has not changed so
+            // {@link SizeConfigurationBuckets#crossedSizeThreshold()} should return false.
+            checkCrossesSizeThreshold(thresholds, oldValue, minValueInBucket, false);
+            checkCrossesSizeThreshold(thresholds, oldValue,
+                    (int) (minValueInBucket + bucketRange * 0.5), false);
+            checkCrossesSizeThreshold(thresholds, oldValue, maxValueInBucket, false);
+            // Test 4 values of size spread outside of bucket range: more than 1 less than min
+            // value, 1 less than min value, 1 more than max value, and more than 1 more than max
+            // value. In all 4 cases, the bucket has changed so
+            // {@link SizeConfigurationBuckets#crossedSizeThreshold()} should return true.
+            // Only test less than min value if min value > 0.
+            if (minValueInBucket > 0) {
+                checkCrossesSizeThreshold(thresholds, oldValue, minValueInBucket - 20, true);
+                checkCrossesSizeThreshold(thresholds, oldValue, minValueInBucket - 1, true);
+            }
+            // Only test greater than max value if not in highest bucket.
+            if (i < nThresholds - 1) {
+                checkCrossesSizeThreshold(thresholds, oldValue, maxValueInBucket + 1, true);
+                checkCrossesSizeThreshold(thresholds, oldValue, maxValueInBucket + 20, true);
+            }
+        }
+    }
+
+    /**
+     * Tests that if screen layout size changed but did not cross a threshold, the filtered diff
+     * does not include screen layout.
+     */
+    @Test
+    public void testScreenLayoutFilteredIfSizeDidNotCrossThreshold() {
+        // Set only small and large sizes
+        final Configuration[] sizeConfigs = new Configuration[2];
+        sizeConfigs[0] = new Configuration();
+        sizeConfigs[0].screenLayout |= SCREENLAYOUT_SIZE_SMALL;
+        sizeConfigs[1] = new Configuration();
+        sizeConfigs[1].screenLayout |= SCREENLAYOUT_SIZE_LARGE;
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(sizeConfigs);
+
+        // Change screen layout size from small to normal and check that screen layout flag is
+        // not part of the diff because a threshold was not crossed.
+        final int diff = CONFIG_SCREEN_LAYOUT;
+        final Configuration oldConfig = new Configuration();
+        oldConfig.screenLayout |= SCREENLAYOUT_SIZE_SMALL;
+        final Configuration newConfig = new Configuration();
+        newConfig.screenLayout |= SCREENLAYOUT_SIZE_NORMAL;
+        final int filteredDiff = SizeConfigurationBuckets.filterDiff(diff, oldConfig, newConfig,
+                sizeBuckets);
+        assertEquals(0, filteredDiff);
+
+        // If a non-size attribute of screen layout changed, then screen layout should not be
+        // filtered from the diff.
+        newConfig.screenLayout |= SCREENLAYOUT_ROUND_YES;
+        final int filteredDiffNonSizeLayoutChanged = SizeConfigurationBuckets.filterDiff(diff,
+                oldConfig, newConfig, sizeBuckets);
+        assertEquals(CONFIG_SCREEN_LAYOUT, filteredDiffNonSizeLayoutChanged);
+    }
+
+    /**
+     * Tests that if screen layout size changed and did cross a threshold, the filtered diff
+     * includes screen layout.
+     */
+    @Test
+    public void testScreenLayoutNotFilteredIfSizeCrossedThreshold() {
+        // Set only small and normal sizes
+        final Configuration[] sizeConfigs = new Configuration[2];
+        sizeConfigs[0] = new Configuration();
+        sizeConfigs[0].screenLayout |= SCREENLAYOUT_SIZE_SMALL;
+        sizeConfigs[1] = new Configuration();
+        sizeConfigs[1].screenLayout |= SCREENLAYOUT_SIZE_NORMAL;
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(sizeConfigs);
+
+        // Change screen layout size from small to normal and check that screen layout flag is
+        // still part of the diff because a threshold was crossed.
+        final int diff = CONFIG_SCREEN_LAYOUT;
+        final Configuration oldConfig = new Configuration();
+        oldConfig.screenLayout |= SCREENLAYOUT_SIZE_SMALL;
+        final Configuration newConfig = new Configuration();
+        newConfig.screenLayout |= SCREENLAYOUT_SIZE_NORMAL;
+        final int filteredDiff = SizeConfigurationBuckets.filterDiff(diff, oldConfig, newConfig,
+                sizeBuckets);
+        assertEquals(CONFIG_SCREEN_LAYOUT, filteredDiff);
+    }
+
+    /**
+     * Tests that anytime screen layout size is decreased, the filtered diff still includes screen
+     * layout.
+     */
+    @Test
+    public void testScreenLayoutNotFilteredIfSizeDecreased() {
+        // The size thresholds can be anything, but can't be null
+        final int[] horizontalThresholds = new int[] { 360, 600 };
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(
+                horizontalThresholds, null /* vertical */, null /* smallest */,
+                null /* screenLayoutSize */, false /* screenLayoutLongSet */);
+        final int[] sizeValuesInOrder = new int[] {
+                SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_LARGE,
+                SCREENLAYOUT_SIZE_XLARGE
+        };
+        final int nSizes = sizeValuesInOrder.length;
+        for (int larger = nSizes - 1; larger > 0; larger--) {
+            for (int smaller = larger - 1; smaller >= 0; smaller--) {
+                final Configuration oldConfig = new Configuration();
+                oldConfig.screenLayout |= sizeValuesInOrder[larger];
+                final Configuration newConfig = new Configuration();
+                newConfig.screenLayout |= sizeValuesInOrder[smaller];
+                assertTrue(String.format("oldSize=%d, newSize=%d", oldConfig.screenLayout,
+                        newConfig.screenLayout),
+                        sizeBuckets.crossesScreenLayoutSizeThreshold(oldConfig, newConfig));
+            }
+        }
+    }
+
+    /**
+     * Tests that if screen layout long changed but did not cross a threshold, the filtered diff
+     * does not include screen layout.
+     */
+    @Test
+    public void testScreenLayoutFilteredIfLongDidNotCrossThreshold() {
+        // Do not set any long threshold
+        final Configuration[] sizeConfigs = new Configuration[1];
+        sizeConfigs[0] = Configuration.EMPTY;
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(sizeConfigs);
+
+        // Change screen layout long from not long to long and check that screen layout flag is
+        // not part of the diff because a threshold was not crossed.
+        final int diff = CONFIG_SCREEN_LAYOUT;
+        final Configuration oldConfig = new Configuration();
+        oldConfig.screenLayout |= SCREENLAYOUT_LONG_NO;
+        final Configuration newConfig = new Configuration();
+        newConfig.screenLayout |= SCREENLAYOUT_LONG_YES;
+        final int filteredDiff = SizeConfigurationBuckets.filterDiff(diff, oldConfig, newConfig,
+                sizeBuckets);
+        assertEquals(0, filteredDiff);
+
+        // If a non-size attribute of screen layout changed, then screen layout should not be
+        // filtered from the diff.
+        newConfig.screenLayout |= SCREENLAYOUT_ROUND_YES;
+        final int filteredDiffNonSizeLayoutChanged = SizeConfigurationBuckets.filterDiff(diff,
+                oldConfig, newConfig, sizeBuckets);
+        assertEquals(CONFIG_SCREEN_LAYOUT, filteredDiffNonSizeLayoutChanged);
+    }
+
+    /**
+     * Tests that if screen layout long changed and did cross a threshold, the filtered diff
+     * includes screen layout.
+     */
+    @Test
+    public void testScreenLayoutNotFilteredIfLongCrossedThreshold() {
+        // Set only small and normal sizes
+        final Configuration[] sizeConfigs = new Configuration[1];
+        sizeConfigs[0] = new Configuration();
+        sizeConfigs[0].screenLayout |= SCREENLAYOUT_LONG_NO;
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(sizeConfigs);
+
+        // Change screen layout long from not long to long and check that screen layout flag is
+        // still part of the diff because a threshold was crossed.
+        final int diff = CONFIG_SCREEN_LAYOUT;
+        final Configuration oldConfig = new Configuration();
+        oldConfig.screenLayout |= SCREENLAYOUT_LONG_NO;
+        final Configuration newConfig = new Configuration();
+        newConfig.screenLayout |= SCREENLAYOUT_LONG_YES;
+        final int filteredDiff = SizeConfigurationBuckets.filterDiff(diff, oldConfig, newConfig,
+                sizeBuckets);
+        assertEquals(CONFIG_SCREEN_LAYOUT, filteredDiff);
+    }
+
+    /**
+     * Tests that horizontal buckets are correctly checked in
+     * {@link SizeConfigurationBuckets#filterDiff()}.
+     */
+    @Test
+    public void testHorizontalSizeThresholds() {
+        final int[] horizontalThresholds = new int[] { 360, 600 };
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(
+                horizontalThresholds, null /* vertical */, null /* smallest */,
+                null /* screenLayoutSize */, false /* screenLayoutLongSet */);
+
+        final Configuration oldConfig = new Configuration();
+        final Configuration newConfig = new Configuration();
+
+        oldConfig.screenWidthDp = 480;
+        // Test that value within bucket filters out screen size config
+        newConfig.screenWidthDp = 520;
+        assertEquals(0, SizeConfigurationBuckets.filterDiff(CONFIG_SCREEN_SIZE, oldConfig,
+                newConfig, sizeBuckets));
+        // Test that value outside bucket does not filter out screen size config
+        newConfig.screenWidthDp = 640;
+        assertEquals(CONFIG_SCREEN_SIZE, SizeConfigurationBuckets.filterDiff(CONFIG_SCREEN_SIZE,
+                oldConfig, newConfig, sizeBuckets));
+    }
+
+    /**
+     * Tests that vertical buckets are correctly checked in
+     * {@link SizeConfigurationBuckets#filterDiff()}.
+     */
+    @Test
+    public void testVerticalSizeThresholds() {
+        final int[] verticalThresholds = new int[] { 360, 600 };
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(
+                null, verticalThresholds /* vertical */, null /* smallest */,
+                null /* screenLayoutSize */, false /* screenLayoutLongSet */);
+
+        final Configuration oldConfig = new Configuration();
+        final Configuration newConfig = new Configuration();
+
+        oldConfig.screenHeightDp = 480;
+        // Test that value within bucket filters out screen size config
+        newConfig.screenHeightDp = 520;
+        assertEquals(0, SizeConfigurationBuckets.filterDiff(CONFIG_SCREEN_SIZE, oldConfig,
+                newConfig, sizeBuckets));
+        // Test that value outside bucket does not filter out screen size config
+        newConfig.screenHeightDp = 640;
+        assertEquals(CONFIG_SCREEN_SIZE, SizeConfigurationBuckets.filterDiff(CONFIG_SCREEN_SIZE,
+                oldConfig, newConfig, sizeBuckets));
+    }
+
+    /**
+     * Tests that smallest width buckets are correctly checked in
+     * {@link SizeConfigurationBuckets#filterDiff()}.
+     */
+    @Test
+    public void testSmallestWidthSizeThresholds() {
+        final int[] smallestWidthThresholds = new int[] { 360, 600 };
+        final SizeConfigurationBuckets sizeBuckets = new SizeConfigurationBuckets(
+                null, null /* vertical */, smallestWidthThresholds /* smallest */,
+                null /* screenLayoutSize */, false /* screenLayoutLongSet */);
+
+        final Configuration oldConfig = new Configuration();
+        final Configuration newConfig = new Configuration();
+
+        oldConfig.smallestScreenWidthDp = 480;
+        // Test that value within bucket filters out smallest screen size config
+        newConfig.smallestScreenWidthDp = 520;
+        assertEquals(0, SizeConfigurationBuckets.filterDiff(CONFIG_SMALLEST_SCREEN_SIZE, oldConfig,
+                newConfig, sizeBuckets));
+        // Test that value outside bucket does not filter out smallest screen size config
+        newConfig.smallestScreenWidthDp = 640;
+        assertEquals(CONFIG_SMALLEST_SCREEN_SIZE, SizeConfigurationBuckets.filterDiff(
+                CONFIG_SMALLEST_SCREEN_SIZE, oldConfig, newConfig, sizeBuckets));
+    }
+
+    private void checkCrossesSizeThreshold(int[] thresholds, int oldValue, int newValue,
+            boolean expected) {
+        final String errorString = String.format(
+                "thresholds=%s, oldValue=%d, newValue=%d, expected=%b", Arrays.toString(thresholds),
+                oldValue, newValue, expected);
+        final boolean actual = SizeConfigurationBuckets.crossesSizeThreshold(thresholds, oldValue,
+                newValue);
+        assertEquals(errorString, expected, actual);
+    }
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index edf473e..b85cb9c 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -542,83 +542,83 @@
     public void testStateMachineEnterExitTransitionToTest() throws Exception {
         //if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
 
-        StateMachineEnterExitTransitionToTest smEnterExitTranstionToTest =
-            new StateMachineEnterExitTransitionToTest("smEnterExitTranstionToTest");
-        smEnterExitTranstionToTest.start();
-        if (smEnterExitTranstionToTest.isDbg()) {
+        StateMachineEnterExitTransitionToTest smEnterExitTransitionToTest =
+                new StateMachineEnterExitTransitionToTest("smEnterExitTransitionToTest");
+        smEnterExitTransitionToTest.start();
+        if (smEnterExitTransitionToTest.isDbg()) {
             tlog("testStateMachineEnterExitTransitionToTest E");
         }
 
-        synchronized (smEnterExitTranstionToTest) {
-            smEnterExitTranstionToTest.sendMessage(TEST_CMD_1);
+        synchronized (smEnterExitTransitionToTest) {
+            smEnterExitTransitionToTest.sendMessage(TEST_CMD_1);
 
             try {
                 // wait for the messages to be handled
-                smEnterExitTranstionToTest.wait();
+                smEnterExitTransitionToTest.wait();
             } catch (InterruptedException e) {
                 tloge("testStateMachineEnterExitTransitionToTest: exception while waiting "
                     + e.getMessage());
             }
         }
 
-        dumpLogRecs(smEnterExitTranstionToTest);
+        dumpLogRecs(smEnterExitTransitionToTest);
 
-        assertEquals(9, smEnterExitTranstionToTest.getLogRecCount());
+        assertEquals(9, smEnterExitTransitionToTest.getLogRecCount());
         LogRec lr;
 
-        lr = smEnterExitTranstionToTest.getLogRec(0);
+        lr = smEnterExitTransitionToTest.getLogRec(0);
         assertEquals(ENTER, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS1, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS1, lr.getState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(1);
+        lr = smEnterExitTransitionToTest.getLogRec(1);
         assertEquals(EXIT, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS1, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS1, lr.getState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(2);
+        lr = smEnterExitTransitionToTest.getLogRec(2);
         assertEquals(ENTER, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(3);
+        lr = smEnterExitTransitionToTest.getLogRec(3);
         assertEquals(TEST_CMD_1, lr.getWhat());
-        assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
-        assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
-        assertEquals(smEnterExitTranstionToTest.mS3, lr.getDestState());
+        assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS2, lr.getOriginalState());
+        assertEquals(smEnterExitTransitionToTest.mS3, lr.getDestState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(4);
+        lr = smEnterExitTransitionToTest.getLogRec(4);
         assertEquals(TEST_CMD_1, lr.getWhat());
-        assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
-        assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+        assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS2, lr.getOriginalState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
         assertEquals(EXIT, lr.getInfo());
 
-        lr = smEnterExitTranstionToTest.getLogRec(5);
+        lr = smEnterExitTransitionToTest.getLogRec(5);
         assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(ENTER, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
-        assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+        assertEquals(smEnterExitTransitionToTest.mS3, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS3, lr.getOriginalState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(6);
+        lr = smEnterExitTransitionToTest.getLogRec(6);
         assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(EXIT, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
-        assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+        assertEquals(smEnterExitTransitionToTest.mS3, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS3, lr.getOriginalState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(7);
+        lr = smEnterExitTransitionToTest.getLogRec(7);
         assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(ENTER, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getOriginalState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
 
-        lr = smEnterExitTranstionToTest.getLogRec(8);
+        lr = smEnterExitTransitionToTest.getLogRec(8);
         assertEquals(TEST_CMD_1, lr.getWhat());
         assertEquals(EXIT, lr.getInfo());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
-        assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getState());
+        assertEquals(smEnterExitTransitionToTest.mS4, lr.getOriginalState());
 
-        if (smEnterExitTranstionToTest.isDbg()) {
+        if (smEnterExitTransitionToTest.isDbg()) {
             tlog("testStateMachineEnterExitTransitionToTest X");
         }
     }
diff --git a/core/tests/uwbtests/AndroidTest.xml b/core/tests/uwbtests/AndroidTest.xml
deleted file mode 100644
index ff4b668..0000000
--- a/core/tests/uwbtests/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2020 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Config for UWB Manager test cases">
-    <option name="test-suite-tag" value="apct"/>
-    <option name="test-suite-tag" value="apct-instrumentation"/>
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="UwbManagerTests.apk" />
-    </target_preparer>
-
-    <option name="test-suite-tag" value="apct"/>
-    <option name="test-tag" value="UwbManagerTests"/>
-
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.uwb" />
-        <option name="hidden-api-checks" value="false"/>
-        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
-    </test>
-</configuration>
diff --git a/core/tests/uwbtests/OWNERS b/core/tests/uwbtests/OWNERS
deleted file mode 100644
index c7b09a2..0000000
--- a/core/tests/uwbtests/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /core/java/android/uwb/OWNERS
diff --git a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
deleted file mode 100644
index 4cad535..0000000
--- a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-
-import android.os.RemoteException;
-import android.uwb.UwbManager.AdapterStateCallback;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link AdapterStateListener}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AdapterStateListenerTest {
-
-    IUwbAdapter mUwbAdapter = mock(IUwbAdapter.class);
-
-    Answer mRegisterSuccessAnswer = new Answer() {
-        public Object answer(InvocationOnMock invocation) {
-            Object[] args = invocation.getArguments();
-            IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
-            try {
-                cb.onAdapterStateChanged(AdapterState.STATE_DISABLED, StateChangeReason.UNKNOWN);
-            } catch (RemoteException e) {
-                // Nothing to do
-            }
-            return new Object();
-        }
-    };
-
-    Throwable mThrowRemoteException = new RemoteException("RemoteException");
-
-    private static Executor getExecutor() {
-        return new Executor() {
-            @Override
-            public void execute(Runnable command) {
-                command.run();
-            }
-        };
-    }
-
-    private static void verifyCallbackStateChangedInvoked(
-            AdapterStateCallback callback, int numTimes) {
-        verify(callback, times(numTimes)).onStateChanged(anyInt(), anyInt());
-    }
-
-    @Test
-    public void testRegister_RegisterUnregister() throws RemoteException {
-        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
-        AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
-
-        // Verify that the adapter state listener registered with the UWB Adapter
-        adapterStateListener.register(getExecutor(), callback1);
-        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
-        verifyCallbackStateChangedInvoked(callback1, 1);
-        verifyCallbackStateChangedInvoked(callback2, 0);
-
-        // Register a second client and no new call to UWB Adapter
-        adapterStateListener.register(getExecutor(), callback2);
-        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
-        verifyCallbackStateChangedInvoked(callback1, 1);
-        verifyCallbackStateChangedInvoked(callback2, 1);
-
-        // Unregister first callback
-        adapterStateListener.unregister(callback1);
-        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
-        verify(mUwbAdapter, times(0)).unregisterAdapterStateCallbacks(any());
-        verifyCallbackStateChangedInvoked(callback1, 1);
-        verifyCallbackStateChangedInvoked(callback2, 1);
-
-        // Unregister second callback
-        adapterStateListener.unregister(callback2);
-        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
-        verify(mUwbAdapter, times(1)).unregisterAdapterStateCallbacks(any());
-        verifyCallbackStateChangedInvoked(callback1, 1);
-        verifyCallbackStateChangedInvoked(callback2, 1);
-    }
-
-    @Test
-    public void testRegister_RegisterSameCallbackTwice() throws RemoteException {
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        AdapterStateCallback callback = mock(AdapterStateCallback.class);
-        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-
-        adapterStateListener.register(getExecutor(), callback);
-        verifyCallbackStateChangedInvoked(callback, 1);
-
-        adapterStateListener.register(getExecutor(), callback);
-        verifyCallbackStateChangedInvoked(callback, 1);
-
-        // Invoke a state change and ensure the callback is only called once
-        adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
-                StateChangeReason.UNKNOWN);
-        verifyCallbackStateChangedInvoked(callback, 2);
-    }
-
-    @Test
-    public void testCallback_RunViaExecutor_Success() throws RemoteException {
-        // Verify that the callbacks are invoked on the executor when successful
-        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-        runViaExecutor();
-    }
-
-    private void runViaExecutor() {
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        AdapterStateCallback callback = mock(AdapterStateCallback.class);
-
-        Executor executor = mock(Executor.class);
-
-        // Do not run commands received and ensure that the callback is not invoked
-        doAnswer(new ExecutorAnswer(false)).when(executor).execute(any());
-        adapterStateListener.register(executor, callback);
-        verify(executor, times(1)).execute(any());
-        verifyCallbackStateChangedInvoked(callback, 0);
-
-        // Manually invoke the callback and ensure callback is not invoked
-        adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
-                StateChangeReason.UNKNOWN);
-        verify(executor, times(2)).execute(any());
-        verifyCallbackStateChangedInvoked(callback, 0);
-
-        // Run the command that the executor receives
-        doAnswer(new ExecutorAnswer(true)).when(executor).execute(any());
-        adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
-                StateChangeReason.UNKNOWN);
-        verify(executor, times(3)).execute(any());
-        verifyCallbackStateChangedInvoked(callback, 1);
-    }
-
-    class ExecutorAnswer implements Answer {
-
-        final boolean mShouldRun;
-        ExecutorAnswer(boolean shouldRun) {
-            mShouldRun = shouldRun;
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) throws Throwable {
-            if (mShouldRun) {
-                ((Runnable) invocation.getArgument(0)).run();
-            }
-            return null;
-        }
-    }
-
-    @Test
-    public void testNotify_AllCallbacksNotified() throws RemoteException {
-        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        List<AdapterStateCallback> callbacks = new ArrayList<>();
-        for (int i = 0; i < 10; i++) {
-            AdapterStateCallback callback = mock(AdapterStateCallback.class);
-            adapterStateListener.register(getExecutor(), callback);
-            callbacks.add(callback);
-        }
-
-            // Ensure every callback got the initial state
-        for (AdapterStateCallback callback : callbacks) {
-            verifyCallbackStateChangedInvoked(callback, 1);
-        }
-
-        // Invoke a state change and ensure all callbacks are invoked
-        adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
-                StateChangeReason.ALL_SESSIONS_CLOSED);
-        for (AdapterStateCallback callback : callbacks) {
-            verifyCallbackStateChangedInvoked(callback, 2);
-        }
-    }
-
-    @Test
-    public void testStateChange_CorrectValue() {
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-
-        AdapterStateCallback callback = mock(AdapterStateCallback.class);
-
-        adapterStateListener.register(getExecutor(), callback);
-
-        runStateChangeValue(StateChangeReason.ALL_SESSIONS_CLOSED,
-                AdapterState.STATE_ENABLED_INACTIVE,
-                AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
-                AdapterStateCallback.STATE_ENABLED_INACTIVE);
-
-        runStateChangeValue(StateChangeReason.SESSION_STARTED, AdapterState.STATE_ENABLED_ACTIVE,
-                AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED,
-                AdapterStateCallback.STATE_ENABLED_ACTIVE);
-
-        runStateChangeValue(StateChangeReason.SYSTEM_BOOT, AdapterState.STATE_DISABLED,
-                AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT,
-                AdapterStateCallback.STATE_DISABLED);
-
-        runStateChangeValue(StateChangeReason.SYSTEM_POLICY, AdapterState.STATE_DISABLED,
-                AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY,
-                AdapterStateCallback.STATE_DISABLED);
-
-        runStateChangeValue(StateChangeReason.UNKNOWN, AdapterState.STATE_DISABLED,
-                AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN,
-                AdapterStateCallback.STATE_DISABLED);
-    }
-
-    private void runStateChangeValue(@StateChangeReason int reasonIn, @AdapterState int stateIn,
-            @AdapterStateCallback.StateChangedReason int reasonOut,
-            @AdapterStateCallback.State int stateOut) {
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        AdapterStateCallback callback = mock(AdapterStateCallback.class);
-        adapterStateListener.register(getExecutor(), callback);
-
-        adapterStateListener.onAdapterStateChanged(stateIn, reasonIn);
-        verify(callback, times(1)).onStateChanged(stateOut, reasonOut);
-    }
-
-    @Test
-    public void testStateChange_FirstRegisterGetsCorrectState() throws RemoteException {
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        AdapterStateCallback callback = mock(AdapterStateCallback.class);
-
-        Answer registerAnswer = new Answer() {
-            public Object answer(InvocationOnMock invocation) {
-                Object[] args = invocation.getArguments();
-                IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
-                try {
-                    cb.onAdapterStateChanged(AdapterState.STATE_ENABLED_ACTIVE,
-                            StateChangeReason.SESSION_STARTED);
-                } catch (RemoteException e) {
-                    // Nothing to do
-                }
-                return new Object();
-            }
-        };
-
-        doAnswer(registerAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-
-        adapterStateListener.register(getExecutor(), callback);
-        verify(callback).onStateChanged(AdapterStateCallback.STATE_ENABLED_ACTIVE,
-                AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
-    }
-
-    @Test
-    public void testStateChange_SecondRegisterGetsCorrectState() {
-        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
-        AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
-        AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
-
-        adapterStateListener.register(getExecutor(), callback1);
-        adapterStateListener.onAdapterStateChanged(AdapterState.STATE_ENABLED_ACTIVE,
-                StateChangeReason.SYSTEM_BOOT);
-
-        adapterStateListener.register(getExecutor(), callback2);
-        verify(callback2).onStateChanged(AdapterStateCallback.STATE_ENABLED_ACTIVE,
-                AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
deleted file mode 100644
index 24267e4..0000000
--- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-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.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.AttributionSource;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link AdapterStateListener}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingManagerTest {
-
-    private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
-    private static final PersistableBundle PARAMS = new PersistableBundle();
-    private static final @RangingChangeReason int REASON = RangingChangeReason.UNKNOWN;
-    private static final int UID = 343453;
-    private static final String PACKAGE_NAME = "com.uwb.test";
-    private static final AttributionSource ATTRIBUTION_SOURCE =
-            new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build();
-
-    @Test
-    public void testOpenSession_OpenRangingInvoked() throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingManager rangingManager = new RangingManager(adapter);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
-        verify(adapter, times(1)).openRanging(
-                eq(ATTRIBUTION_SOURCE), any(), any(), any());
-    }
-
-    @Test
-    public void testOnRangingOpened_InvalidSessionHandle() throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingManager rangingManager = new RangingManager(adapter);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-
-        rangingManager.onRangingOpened(new SessionHandle(2));
-        verify(callback, times(0)).onOpened(any());
-    }
-
-    @Test
-    public void testOnRangingOpened_MultipleSessionsRegistered() throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
-        RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
-        ArgumentCaptor<SessionHandle> sessionHandleCaptor =
-                ArgumentCaptor.forClass(SessionHandle.class);
-
-        RangingManager rangingManager = new RangingManager(adapter);
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback1);
-        verify(adapter, times(1)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
-
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback2);
-        verify(adapter, times(2)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
-
-        rangingManager.onRangingOpened(sessionHandle1);
-        verify(callback1, times(1)).onOpened(any());
-        verify(callback2, times(0)).onOpened(any());
-
-        rangingManager.onRangingOpened(sessionHandle2);
-        verify(callback1, times(1)).onOpened(any());
-        verify(callback2, times(1)).onOpened(any());
-    }
-
-    @Test
-    public void testCorrectCallbackInvoked() throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingManager rangingManager = new RangingManager(adapter);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-
-        ArgumentCaptor<SessionHandle> sessionHandleCaptor =
-                ArgumentCaptor.forClass(SessionHandle.class);
-
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
-        verify(adapter, times(1)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle handle = sessionHandleCaptor.getValue();
-
-        rangingManager.onRangingOpened(handle);
-        verify(callback, times(1)).onOpened(any());
-
-        rangingManager.onRangingStarted(handle, PARAMS);
-        verify(callback, times(1)).onStarted(eq(PARAMS));
-
-        rangingManager.onRangingStartFailed(handle, REASON, PARAMS);
-        verify(callback, times(1)).onStartFailed(eq(REASON), eq(PARAMS));
-
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        rangingManager.onRangingResult(handle, report);
-        verify(callback, times(1)).onReportReceived(eq(report));
-
-        rangingManager.onRangingReconfigured(handle, PARAMS);
-        verify(callback, times(1)).onReconfigured(eq(PARAMS));
-
-        rangingManager.onRangingReconfigureFailed(handle, REASON, PARAMS);
-        verify(callback, times(1)).onReconfigureFailed(eq(REASON), eq(PARAMS));
-
-        rangingManager.onRangingStopped(handle, REASON, PARAMS);
-        verify(callback, times(1)).onStopped(eq(REASON), eq(PARAMS));
-
-        rangingManager.onRangingStopFailed(handle, REASON, PARAMS);
-        verify(callback, times(1)).onStopFailed(eq(REASON), eq(PARAMS));
-
-        rangingManager.onRangingClosed(handle, REASON, PARAMS);
-        verify(callback, times(1)).onClosed(eq(REASON), eq(PARAMS));
-    }
-
-    @Test
-    public void testOnRangingClosed_MultipleSessionsRegistered() throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        // Verify that if multiple sessions are registered, only the session that is
-        // requested to close receives the associated callbacks
-        RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
-        RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
-
-        RangingManager rangingManager = new RangingManager(adapter);
-        ArgumentCaptor<SessionHandle> sessionHandleCaptor =
-                ArgumentCaptor.forClass(SessionHandle.class);
-
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback1);
-        verify(adapter, times(1)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
-
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback2);
-        verify(adapter, times(2)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
-
-        rangingManager.onRangingClosed(sessionHandle1, REASON, PARAMS);
-        verify(callback1, times(1)).onClosed(anyInt(), any());
-        verify(callback2, times(0)).onClosed(anyInt(), any());
-
-        rangingManager.onRangingClosed(sessionHandle2, REASON, PARAMS);
-        verify(callback1, times(1)).onClosed(anyInt(), any());
-        verify(callback2, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingReport_MultipleSessionsRegistered() throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
-        RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
-
-        ArgumentCaptor<SessionHandle> sessionHandleCaptor =
-                ArgumentCaptor.forClass(SessionHandle.class);
-
-        RangingManager rangingManager = new RangingManager(adapter);
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback1);
-        verify(adapter, times(1)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
-
-        rangingManager.onRangingStarted(sessionHandle1, PARAMS);
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback2);
-        verify(adapter, times(2)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
-        rangingManager.onRangingStarted(sessionHandle2, PARAMS);
-
-        rangingManager.onRangingResult(sessionHandle1, UwbTestUtils.getRangingReports(1));
-        verify(callback1, times(1)).onReportReceived(any());
-        verify(callback2, times(0)).onReportReceived(any());
-
-        rangingManager.onRangingResult(sessionHandle2, UwbTestUtils.getRangingReports(1));
-        verify(callback1, times(1)).onReportReceived(any());
-        verify(callback2, times(1)).onReportReceived(any());
-    }
-
-    @Test
-    public void testReasons() throws RemoteException {
-        runReason(RangingChangeReason.LOCAL_API,
-                RangingSession.Callback.REASON_LOCAL_REQUEST);
-
-        runReason(RangingChangeReason.MAX_SESSIONS_REACHED,
-                RangingSession.Callback.REASON_MAX_SESSIONS_REACHED);
-
-        runReason(RangingChangeReason.PROTOCOL_SPECIFIC,
-                RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR);
-
-        runReason(RangingChangeReason.REMOTE_REQUEST,
-                RangingSession.Callback.REASON_REMOTE_REQUEST);
-
-        runReason(RangingChangeReason.SYSTEM_POLICY,
-                RangingSession.Callback.REASON_SYSTEM_POLICY);
-
-        runReason(RangingChangeReason.BAD_PARAMETERS,
-                RangingSession.Callback.REASON_BAD_PARAMETERS);
-
-        runReason(RangingChangeReason.UNKNOWN,
-                RangingSession.Callback.REASON_UNKNOWN);
-    }
-
-    private void runReason(@RangingChangeReason int reasonIn,
-            @RangingSession.Callback.Reason int reasonOut) throws RemoteException {
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingManager rangingManager = new RangingManager(adapter);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-
-        ArgumentCaptor<SessionHandle> sessionHandleCaptor =
-                ArgumentCaptor.forClass(SessionHandle.class);
-
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
-        verify(adapter, times(1)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        SessionHandle handle = sessionHandleCaptor.getValue();
-
-        rangingManager.onRangingOpenFailed(handle, reasonIn, PARAMS);
-        verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS));
-
-        // Open a new session
-        rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
-        verify(adapter, times(2)).openRanging(
-                eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
-        handle = sessionHandleCaptor.getValue();
-        rangingManager.onRangingOpened(handle);
-
-        rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
-        verify(callback, times(1)).onStartFailed(eq(reasonOut), eq(PARAMS));
-
-        rangingManager.onRangingReconfigureFailed(handle, reasonIn, PARAMS);
-        verify(callback, times(1)).onReconfigureFailed(eq(reasonOut), eq(PARAMS));
-
-        rangingManager.onRangingStopFailed(handle, reasonIn, PARAMS);
-        verify(callback, times(1)).onStopFailed(eq(reasonOut), eq(PARAMS));
-
-        rangingManager.onRangingClosed(handle, reasonIn, PARAMS);
-        verify(callback, times(1)).onClosed(eq(reasonOut), eq(PARAMS));
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
deleted file mode 100644
index 75c6924..0000000
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb;
-
-import android.os.SystemClock;
-
-import java.util.concurrent.Executor;
-
-public class UwbTestUtils {
-    private UwbTestUtils() {}
-
-    public static AngleMeasurement getAngleMeasurement() {
-        return new AngleMeasurement(
-                getDoubleInRange(-Math.PI, Math.PI),
-                getDoubleInRange(0, Math.PI),
-                getDoubleInRange(0, 1));
-    }
-
-    public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
-        return new AngleOfArrivalMeasurement.Builder(getAngleMeasurement())
-                .setAltitude(getAngleMeasurement())
-                .build();
-    }
-
-    public static DistanceMeasurement getDistanceMeasurement() {
-        return new DistanceMeasurement.Builder()
-                .setMeters(getDoubleInRange(0, 100))
-                .setErrorMeters(getDoubleInRange(0, 10))
-                .setConfidenceLevel(getDoubleInRange(0, 1))
-                .build();
-    }
-
-    public static RangingMeasurement getRangingMeasurement() {
-        return getRangingMeasurement(getUwbAddress(false));
-    }
-
-    public static RangingMeasurement getRangingMeasurement(UwbAddress address) {
-        return new RangingMeasurement.Builder()
-                .setDistanceMeasurement(getDistanceMeasurement())
-                .setAngleOfArrivalMeasurement(getAngleOfArrivalMeasurement())
-                .setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
-                .setRemoteDeviceAddress(address != null ? address : getUwbAddress(false))
-                .setStatus(RangingMeasurement.RANGING_STATUS_SUCCESS)
-                .build();
-    }
-
-    public static RangingReport getRangingReports(int numMeasurements) {
-        RangingReport.Builder builder = new RangingReport.Builder();
-        for (int i = 0; i < numMeasurements; i++) {
-            builder.addMeasurement(getRangingMeasurement());
-        }
-        return builder.build();
-    }
-
-    private static double getDoubleInRange(double min, double max) {
-        return min + (max - min) * Math.random();
-    }
-
-    public static UwbAddress getUwbAddress(boolean isShortAddress) {
-        byte[] addressBytes = new byte[isShortAddress ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH :
-                UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH];
-        for (int i = 0; i < addressBytes.length; i++) {
-            addressBytes[i] = (byte) getDoubleInRange(1, 255);
-        }
-        return UwbAddress.fromBytes(addressBytes);
-    }
-
-    public static Executor getExecutor() {
-        return new Executor() {
-            @Override
-            public void execute(Runnable command) {
-                command.run();
-            }
-        };
-    }
-}
diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml
index abde232..33f885a 100644
--- a/data/etc/car/com.android.car.carlauncher.xml
+++ b/data/etc/car/com.android.car.carlauncher.xml
@@ -17,6 +17,7 @@
 <permissions>
     <privapp-permissions package="com.android.car.carlauncher">
         <permission name="android.permission.ACTIVITY_EMBEDDING"/>
+        <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 8caff23..0d7225b 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -211,6 +211,12 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
     },
+    "-1898316768": {
+      "message": "Unable to retrieve window container to start layer mirroring for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-1895337367": {
       "message": "Delete root task display=%d winMode=%d",
       "level": "VERBOSE",
@@ -571,6 +577,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
+    "-1483435730": {
+      "message": "InsetsSource setWin %s for type %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
     "-1480772131": {
       "message": "No app or window is requesting an orientation, return %d for display id=%d",
       "level": "VERBOSE",
@@ -673,6 +685,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
     },
+    "-1394745488": {
+      "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
     "-1391944764": {
       "message": "SURFACE DESTROY: %s. %s",
       "level": "INFO",
@@ -721,12 +739,6 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "-1312861660": {
-      "message": "notifyInsetsControlChanged for %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
     "-1311436264": {
       "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
       "level": "VERBOSE",
@@ -835,6 +847,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "-1185473319": {
+      "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
     "-1176488860": {
       "message": "SURFACE isSecure=%b: %s",
       "level": "INFO",
@@ -1081,6 +1099,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-904499590": {
+      "message": "Provided surface for layer mirroring on display %d is not present, so do not update the surface",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-883738232": {
       "message": "Adding more than one toast window for UID at a time.",
       "level": "WARN",
@@ -1249,6 +1273,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-702650156": {
+      "message": "Override with TaskFragment remote animation for transit=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
     "-701167286": {
       "message": "applyAnimation: transit=%s, enter=%b, wc=%s",
       "level": "VERBOSE",
@@ -1285,6 +1315,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-663411559": {
+      "message": "Going ahead with updating layer mirroring for display %d to new bounds %s and\/or orientation %d.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-655104359": {
       "message": "Frontmost changed immersion: %s",
       "level": "DEBUG",
@@ -1531,12 +1567,6 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
-    "-395922585": {
-      "message": "InsetsSource setWin %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
     "-393505149": {
       "message": "unable to update pointer icon",
       "level": "WARN",
@@ -1549,6 +1579,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-384564722": {
+      "message": "Unable to start layer mirroring for display %d since the surface is not available.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-381475323": {
       "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
       "level": "DEBUG",
@@ -1621,6 +1657,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "-309399422": {
+      "message": "Display %d state is now (%d), so update layer mirroring?",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-302468788": {
       "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
       "level": "WARN",
@@ -1687,6 +1729,12 @@
       "group": "WM_DEBUG_WINDOW_MOVEMENT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-190034097": {
+      "message": "Unable to retrieve window container to update layer mirroring for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-177040661": {
       "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
       "level": "DEBUG",
@@ -1741,12 +1789,6 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-112805366": {
-      "message": "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
     "-108977760": {
       "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
       "level": "DEBUG",
@@ -1789,6 +1831,18 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "-79877120": {
+      "message": "Display %d has content (%b) so disable layer mirroring",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-70719599": {
+      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "-55185509": {
       "message": "setFocusedTask: taskId=%d touchedActivity=%s",
       "level": "DEBUG",
@@ -1849,12 +1903,6 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
-    "29780972": {
-      "message": "InsetsSource Control %s for target %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
     "35398067": {
       "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
       "level": "DEBUG",
@@ -1897,24 +1945,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
-    "73987756": {
-      "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
     "74885950": {
       "message": "Waiting for top state to be released by %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
     },
-    "75707221": {
-      "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
     "83950285": {
       "message": "removeAnimation(%d)",
       "level": "DEBUG",
@@ -2287,6 +2323,12 @@
       "group": "WM_SHOW_SURFACE_ALLOC",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "416924848": {
+      "message": "InsetsSource Control %s for target %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
     "417311568": {
       "message": "onResize: Resizing %s",
       "level": "DEBUG",
@@ -2347,6 +2389,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
     },
+    "504397469": {
+      "message": "Unable to update layer mirroring for display %d to new bounds %s and\/or orientation %d, since the surface is not available.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "508887531": {
       "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
       "level": "VERBOSE",
@@ -2599,6 +2647,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "743418423": {
+      "message": "Sending TaskFragment error exception=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "744171317": {
       "message": "      SKIP: %s",
       "level": "VERBOSE",
@@ -2797,6 +2851,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1030898920": {
+      "message": "notifyInsetsControlChanged for %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "1033274509": {
       "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
       "level": "WARN",
@@ -2815,6 +2875,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1047505501": {
+      "message": "notifyInsetsChanged for %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "1047769218": {
       "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
       "level": "VERBOSE",
@@ -2935,6 +3001,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1210037962": {
+      "message": "Register remote animations for organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "1219600119": {
       "message": "addWindow: win=%s Callers=%s",
       "level": "DEBUG",
@@ -3079,6 +3151,12 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1407569006": {
+      "message": "Display %d was already layer mirroring, so apply transformations if necessary",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "1417601133": {
       "message": "Enqueueing ADD_STARTING",
       "level": "VERBOSE",
@@ -3205,12 +3283,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1533154777": {
-      "message": "notifyInsetsChanged for %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
     "1557732761": {
       "message": "For Intent %s bringing to top: %s",
       "level": "DEBUG",
@@ -3331,6 +3403,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1687376052": {
+      "message": "Display %d has no content and is on, so start layer mirroring for state %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_LAYER_MIRRORING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "1689989893": {
       "message": "SyncGroup %d: Set ready",
       "level": "VERBOSE",
@@ -3637,6 +3715,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "2070726247": {
+      "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
     "2083556954": {
       "message": "Set mOrientationChanging of %s",
       "level": "VERBOSE",
@@ -3729,6 +3813,9 @@
     "WM_DEBUG_KEEP_SCREEN_ON": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_LAYER_MIRRORING": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_LOCKTASK": {
       "tag": "WindowManager"
     },
@@ -3762,6 +3849,9 @@
     "WM_DEBUG_TASKS": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_WINDOW_INSETS": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_WINDOW_MOVEMENT": {
       "tag": "WindowManager"
     },
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index c6c7d3b..a3495209 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -24,18 +24,13 @@
     $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
     $(LOCAL_PATH)/alarms/ogg/Barium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Barium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \
     $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \
     $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
     $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Promethium.ogg \
     $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Scandium.ogg \
     $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
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 36215ec..0e1360f 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -39,6 +39,7 @@
                                                               long frameNumber);
     private static native void nativeSetTransactionCompleteCallback(long ptr, long frameNumber,
             TransactionCompleteCallback callback);
+    private static native long nativeGetLastAcquiredFrameNum(long ptr);
 
     /**
      * Callback sent to {@link #setTransactionCompleteCallback(long, TransactionCompleteCallback)}
@@ -145,4 +146,7 @@
         nativeMergeWithNextTransaction(mNativeObject, nativeTransaction, frameNumber);
     }
 
+    public long getLastAcquiredFrameNum() {
+        return nativeGetLastAcquiredFrameNum(mNativeObject);
+    }
 }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 81aeec0..abf7e99 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1272,11 +1272,10 @@
      * in a way similar to quickReject, in that it tells you that drawing
      * outside of these bounds will be clipped out.
      *
-     * @param bounds Return the clip bounds here. If it is null, ignore it but
-     *               still return true if the current clip is non-empty.
+     * @param bounds Return the clip bounds here.
      * @return true if the current clip is non-empty.
      */
-    public boolean getClipBounds(@Nullable Rect bounds) {
+    public boolean getClipBounds(@NonNull Rect bounds) {
         return nGetClipBounds(mNativeCanvasWrapper, bounds);
     }
 
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index ac2d0c4..abdf1a2 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -388,7 +388,8 @@
          */
         public @NonNull FrameRenderRequest setFrameCommitCallback(@NonNull Executor executor,
                 @NonNull Runnable frameCommitCallback) {
-            setFrameCompleteCallback(frameNr -> executor.execute(frameCommitCallback));
+            nSetFrameCommitCallback(mNativeProxy,
+                    didProduceBuffer -> executor.execute(frameCommitCallback));
             return this;
         }
 
@@ -609,6 +610,11 @@
     }
 
     /** @hide */
+    public void setFrameCommitCallback(FrameCommitCallback callback) {
+        nSetFrameCommitCallback(mNativeProxy, callback);
+    }
+
+    /** @hide */
     public void setFrameCompleteCallback(FrameCompleteCallback callback) {
         nSetFrameCompleteCallback(mNativeProxy, callback);
     }
@@ -752,22 +758,14 @@
         nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
     }
 
-    private ASurfaceTransactionCallback mASurfaceTransactionCallback;
-
     /** @hide */
-    public void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) {
-        // ensure callback is kept alive on the java side since weak ref is used in native code
-        mASurfaceTransactionCallback = callback;
+    protected void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) {
         nSetASurfaceTransactionCallback(mNativeProxy, callback);
     }
 
-    private PrepareSurfaceControlForWebviewCallback mAPrepareSurfaceControlForWebviewCallback;
-
     /** @hide */
-    public void setPrepareSurfaceControlForWebviewCallback(
+    protected void setPrepareSurfaceControlForWebviewCallback(
             PrepareSurfaceControlForWebviewCallback callback) {
-        // ensure callback is kept alive on the java side since weak ref is used in native code
-        mAPrepareSurfaceControlForWebviewCallback = callback;
         nSetPrepareSurfaceControlForWebviewCallback(mNativeProxy, callback);
     }
 
@@ -904,13 +902,27 @@
      *
      * @hide
      */
+    public interface FrameCommitCallback {
+        /**
+         * Invoked after a new frame was drawn
+         *
+         * @param didProduceBuffer The draw successfully produced a new buffer.
+         */
+        void onFrameCommit(boolean didProduceBuffer);
+    }
+
+    /**
+     * Interface used to be notified when RenderThread has finished an attempt to draw. This doesn't
+     * mean a new frame has drawn, specifically if there's nothing new to draw, but only that
+     * RenderThread had a chance to draw a frame.
+     *
+     * @hide
+     */
     public interface FrameCompleteCallback {
         /**
-         * Invoked after a frame draw
-         *
-         * @param frameNr The id of the frame that was drawn.
+         * Invoked after a frame draw was attempted.
          */
-        void onFrameComplete(long frameNr);
+        void onFrameComplete();
     }
 
     /**
@@ -1299,7 +1311,7 @@
     /**
      * @hide
      */
-    public static native boolean isWebViewOverlaysEnabled();
+    protected static native boolean isWebViewOverlaysEnabled();
 
     /** @hide */
     protected static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
@@ -1399,6 +1411,9 @@
 
     private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
 
+    private static native void nSetFrameCommitCallback(long nativeProxy,
+            FrameCommitCallback callback);
+
     private static native void nSetFrameCompleteCallback(long nativeProxy,
             FrameCompleteCallback callback);
 
diff --git a/graphics/java/android/graphics/HardwareRendererObserver.java b/graphics/java/android/graphics/HardwareRendererObserver.java
index e2a0572..d5a6a2f 100644
--- a/graphics/java/android/graphics/HardwareRendererObserver.java
+++ b/graphics/java/android/graphics/HardwareRendererObserver.java
@@ -21,12 +21,14 @@
 
 import com.android.internal.util.VirtualRefBasePtr;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Provides streaming access to frame stats information from HardwareRenderer to apps.
  *
  * @hide
  */
-public class HardwareRendererObserver {
+public final class HardwareRendererObserver {
     private final long[] mFrameMetrics;
     private final Handler mHandler;
     private final OnFrameMetricsAvailableListener mListener;
@@ -74,15 +76,14 @@
         mFrameMetrics = frameMetrics;
         mHandler = handler;
         mListener = listener;
-        mNativePtr = new VirtualRefBasePtr(nCreateObserver(waitForPresentTime));
+        mNativePtr = new VirtualRefBasePtr(nCreateObserver(
+                new WeakReference<>(this), waitForPresentTime));
     }
 
     /*package*/ long getNativeInstance() {
         return mNativePtr.get();
     }
 
-    // Called by native on the provided Handler
-    @SuppressWarnings("unused")
     private void notifyDataAvailable() {
         mHandler.post(() -> {
             boolean hasMoreData = true;
@@ -98,6 +99,21 @@
         });
     }
 
-    private native long nCreateObserver(boolean waitForPresentTime);
+    /**
+     * called by native
+     * @hide
+     * @return true to keep listening, false if this is a dead observer
+     */
+    static boolean invokeDataAvailable(WeakReference<HardwareRendererObserver> weakObserver) {
+        HardwareRendererObserver observer = weakObserver.get();
+        if (observer != null) {
+            observer.notifyDataAvailable();
+            return true;
+        }
+        return false;
+    }
+
+    private static native long nCreateObserver(WeakReference<HardwareRendererObserver> observer,
+            boolean waitForPresentTime);
     private static native int nGetNextBuffer(long nativePtr, long[] data);
 }
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 5b79d76..884d27f 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -178,22 +178,8 @@
      * <p>Android YUV P010 format.</p>
      *
      * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
-     * followed immediately by a Wx(H/2) CbCr plane. Each sample is
-     * represented by a 16-bit little-endian value, with the lower 6 bits set
-     * to zero.
-     *
-     * <p>This format assumes
-     * <ul>
-     * <li>an even height</li>
-     * <li>a vertical stride equal to the height</li>
-     * </ul>
-     * </p>
-     *
-     * <pre>   stride_in_bytes = stride * 2 </pre>
-     * <pre>   y_size = stride_in_bytes * height </pre>
-     * <pre>   cbcr_size = stride_in_bytes * (height / 2) </pre>
-     * <pre>   cb_offset = y_size </pre>
-     * <pre>   cr_offset = cb_offset + 2 </pre>
+     * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+     * little-endian value, with the lower 6 bits set to zero.
      *
      * <p>For example, the {@link android.media.Image} object can provide data
      * in this format from a {@link android.hardware.camera2.CameraDevice}
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/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 4925209..872331c 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -67,7 +67,7 @@
 
     @NonNull RippleAnimationSession enter(Canvas canvas) {
         mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        if (isHwAccelerated(canvas)) {
+        if (useRTAnimations(canvas)) {
             enterHardware((RecordingCanvas) canvas);
         } else {
             enterSoftware();
@@ -82,7 +82,7 @@
     }
 
     @NonNull RippleAnimationSession exit(Canvas canvas) {
-        if (isHwAccelerated(canvas)) exitHardware((RecordingCanvas) canvas);
+        if (useRTAnimations(canvas)) exitHardware((RecordingCanvas) canvas);
         else exitSoftware();
         return this;
     }
@@ -102,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() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index d3cff5c..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.
@@ -848,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/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java
index 053bec74..2e54e63 100644
--- a/keystore/java/android/security/GenerateRkpKey.java
+++ b/keystore/java/android/security/GenerateRkpKey.java
@@ -25,6 +25,8 @@
 import android.util.Log;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -88,7 +90,8 @@
         }
         intent.setComponent(comp);
         mCountDownLatch = new CountDownLatch(1);
-        if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+        Executor executor = Executors.newCachedThreadPool();
+        if (!mContext.bindService(intent, Context.BIND_AUTO_CREATE, executor, mConnection)) {
             throw new RemoteException("Failed to bind to GenerateRkpKeyService");
         }
         try {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
index 5619585..b24a22d 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
@@ -102,11 +102,9 @@
         final int prime = 31;
         int result = 1;
 
-        result = prime * result + ((mDescriptor == null) ? 0 : mDescriptor.hashCode());
+        result = prime * result + getClass().hashCode();
         result = prime * result + (int) (mKeyId >>> 32);
         result = prime * result + (int) (mKeyId & 0xffffffff);
-        result = prime * result + ((mAuthorizations == null) ? 0 : mAuthorizations.hashCode());
-        result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
         return result;
     }
 
@@ -122,10 +120,6 @@
             return false;
         }
         AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
-        if (mKeyId != other.mKeyId) {
-            return false;
-        }
-
-        return true;
+        return mKeyId == other.mKeyId;
     }
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
index db3e567..4842984 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
@@ -23,6 +23,7 @@
 import android.system.keystore2.KeyMetadata;
 
 import java.security.PublicKey;
+import java.util.Objects;
 
 /**
  * {@link PublicKey} backed by Android Keystore.
@@ -75,9 +76,14 @@
         if (!super.equals(obj)) {
             return false;
         }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        return true;
+
+        /*
+         * getClass().equals(ojb.getClass()) is implied by the call to super.equals() above. This
+         * means we can cast obj to AndroidKeyStorePublicKey here.
+         */
+        final AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
+
+        return Objects.equals(mCertificate, other.mCertificate) && Objects.equals(mCertificateChain,
+                other.mCertificateChain);
     }
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index f3cfcf1..67358c4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -579,7 +579,7 @@
         //
         // Note: mNamespace == KeyProperties.NAMESPACE_APPLICATION implies that the target domain
         // is Domain.APP and Domain.SELINUX is the target domain otherwise.
-        if (alias != descriptor.alias
+        if (!alias.equals(descriptor.alias)
                 || descriptor.domain != targetDomain
                 || (descriptor.domain == Domain.SELINUX && descriptor.nspace != targetNamespace)) {
             throw new KeyStoreException("Can only replace keys with same alias: " + alias
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
index b7a6039..ce4e103 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
@@ -18,6 +18,10 @@
 
 import android.content.Context;
 
+import androidx.annotation.NonNull;
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.organizer.EmbeddingExtensionImpl;
+
 /**
  * Provider class that will instantiate the library implementation. It must be included in the
  * vendor library, and the vendor implementation must match the signature of this class.
@@ -31,6 +35,12 @@
         return new SampleExtensionImpl(context);
     }
 
+    /** Provides a reference implementation of {@link ActivityEmbeddingComponent}. */
+    public static ActivityEmbeddingComponent getActivityEmbeddingExtensionImpl(
+            @NonNull Context context) {
+        return new EmbeddingExtensionImpl();
+    }
+
     /**
      * The support library will use this method to check API version compatibility.
      * @return API version string in MAJOR.MINOR.PATCH-description format.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
index cafc233..a0d5b00 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
@@ -23,19 +23,15 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.Rect;
-import android.os.Bundle;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.window.common.DeviceStateManagerPostureProducer;
 import androidx.window.common.DisplayFeature;
 import androidx.window.common.ResourceConfigDisplayFeatureProducer;
 import androidx.window.common.SettingsDevicePostureProducer;
 import androidx.window.common.SettingsDisplayFeatureProducer;
-import androidx.window.extensions.organizer.SplitController;
 import androidx.window.util.DataProducer;
 import androidx.window.util.PriorityDataProducer;
 
@@ -60,8 +56,6 @@
     private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
     private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
 
-    private final SplitController mSplitController;
-
     SampleExtensionImpl(Context context) {
         mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
         mDevicePostureProducer = new PriorityDataProducer<>(List.of(
@@ -77,8 +71,6 @@
 
         mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
         mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
-
-        mSplitController = new SplitController();
     }
 
     private int getFeatureState(DisplayFeature feature) {
@@ -142,28 +134,4 @@
 
         onDisplayFeaturesChanged();
     }
-
-    @Override
-    public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
-        mSplitController.setSplitRules(splitRules);
-    }
-
-    @Override
-    @NonNull
-    public List<ExtensionSplitRule> getSplitRules() {
-        return new ArrayList<>(mSplitController.getSplitRules());
-    }
-
-    @Override
-    public void setSplitOrganizerCallback(@Nullable SplitOrganizerCallback callback) {
-        mSplitController.setSplitOrganizerCallback(callback);
-    }
-
-    @Override
-    public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
-            @Nullable Bundle options, @NonNull ExtensionSplitPairRule splitPairRule,
-            int startRequestId) {
-        mSplitController.startActivityToSide(launchingActivity, intent, options, splitPairRule,
-                startRequestId);
-    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/EmbeddingExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/EmbeddingExtensionImpl.java
new file mode 100644
index 0000000..9a8961f
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/EmbeddingExtensionImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.organizer;
+
+import androidx.annotation.NonNull;
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.EmbeddingRule;
+import androidx.window.extensions.embedding.SplitInfo;
+
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Reference implementation of the activity embedding interface defined in WM Jetpack.
+ */
+public class EmbeddingExtensionImpl implements ActivityEmbeddingComponent {
+
+    private final SplitController mSplitController;
+
+    public EmbeddingExtensionImpl() {
+        mSplitController = new SplitController();
+    }
+
+    @Override
+    public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
+        mSplitController.setEmbeddingRules(rules);
+    }
+
+    @Override
+    public void setEmbeddingCallback(@NonNull Consumer<List<SplitInfo>> consumer) {
+        mSplitController.setEmbeddingCallback(consumer);
+    }
+}
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 531df30..9212a0f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -36,6 +36,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.window.extensions.embedding.SplitRule;
 
 import java.util.Map;
 import java.util.concurrent.Executor;
@@ -61,6 +62,7 @@
     final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>();
 
     private final TaskFragmentCallback mCallback;
+    private TaskFragmentAnimationController mAnimationController;
 
     /**
      * Callback that notifies the controller about changes to task fragments.
@@ -82,6 +84,25 @@
         mCallback = callback;
     }
 
+    @Override
+    public void registerOrganizer() {
+        if (mAnimationController != null) {
+            throw new IllegalStateException("Must unregister the organizer before re-register.");
+        }
+        super.registerOrganizer();
+        mAnimationController = new TaskFragmentAnimationController(this);
+        mAnimationController.registerRemoteAnimations();
+    }
+
+    @Override
+    public void unregisterOrganizer() {
+        if (mAnimationController != null) {
+            mAnimationController.unregisterRemoteAnimations();
+            mAnimationController = null;
+        }
+        super.unregisterOrganizer();
+    }
+
     /**
      * Starts a new Activity and puts it into split with an existing Activity side-by-side.
      * @param launchingFragmentToken    token for the launching TaskFragment. If it exists, it will
@@ -96,11 +117,11 @@
      * @param activityIntent    Intent to start the secondary Activity with.
      * @param activityOptions   ActivityOptions to start the secondary Activity with.
      */
-    void startActivityToSide(IBinder launchingFragmentToken, Rect launchingFragmentBounds,
-            Activity launchingActivity, IBinder secondaryFragmentToken,
-            Rect secondaryFragmentBounds,  Intent activityIntent,
-            @Nullable Bundle activityOptions) {
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
+    void startActivityToSide(@NonNull WindowContainerTransaction wct,
+            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds,
+            @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
+            @NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent,
+            @Nullable Bundle activityOptions, @NonNull SplitRule rule) {
         final IBinder ownerToken = launchingActivity.getActivityToken();
 
         // Create or resize the launching TaskFragment.
@@ -117,9 +138,7 @@
                 activityOptions);
 
         // Set adjacent to each other so that the containers below will be invisible.
-        wct.setAdjacentTaskFragments(launchingFragmentToken, secondaryFragmentToken);
-
-        applyTransaction(wct);
+        setAdjacentTaskFragments(wct, launchingFragmentToken, secondaryFragmentToken, rule);
     }
 
     /**
@@ -129,7 +148,7 @@
      */
     void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
         resizeTaskFragment(wct, fragmentToken, new Rect());
-        wct.setAdjacentTaskFragments(fragmentToken, null);
+        setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */);
     }
 
     /**
@@ -189,6 +208,21 @@
         wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
     }
 
+    void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
+            @NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) {
+        WindowContainerTransaction.TaskFragmentAdjacentOptions adjacentOptions = null;
+        final boolean finishSecondaryWithPrimary =
+                splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule);
+        final boolean finishPrimaryWithSecondary =
+                splitRule != null && SplitContainer.shouldFinishPrimaryWithSecondary(splitRule);
+        if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) {
+            adjacentOptions = new WindowContainerTransaction.TaskFragmentAdjacentOptions();
+            adjacentOptions.setDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary);
+            adjacentOptions.setDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary);
+        }
+        wct.setAdjacentTaskFragments(primary, secondary, adjacentOptions);
+    }
+
     TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
             Rect bounds, @WindowingMode int windowingMode) {
         if (mFragmentInfos.containsKey(fragmentToken)) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
index ade8573..a41557d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
@@ -19,7 +19,9 @@
 import android.annotation.NonNull;
 import android.app.Activity;
 
-import androidx.window.extensions.ExtensionSplitPairRule;
+import androidx.window.extensions.embedding.SplitPairRule;
+import androidx.window.extensions.embedding.SplitPlaceholderRule;
+import androidx.window.extensions.embedding.SplitRule;
 
 /**
  * Client-side descriptor of a split that holds two containers.
@@ -27,20 +29,28 @@
 class SplitContainer {
     private final TaskFragmentContainer mPrimaryContainer;
     private final TaskFragmentContainer mSecondaryContainer;
-    private final ExtensionSplitPairRule mSplitPairRule;
+    private final SplitRule mSplitRule;
 
     SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
             @NonNull Activity primaryActivity,
             @NonNull TaskFragmentContainer secondaryContainer,
-            @NonNull ExtensionSplitPairRule splitPairRule) {
+            @NonNull SplitRule splitRule) {
         mPrimaryContainer = primaryContainer;
         mSecondaryContainer = secondaryContainer;
-        mSplitPairRule = splitPairRule;
+        mSplitRule = splitRule;
 
-        if (mSplitPairRule.finishPrimaryWithSecondary || mSplitPairRule.useAsPlaceholder) {
-            mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
+        if (shouldFinishPrimaryWithSecondary(splitRule)) {
+            if (mPrimaryContainer.getRunningActivityCount() == 1
+                    && mPrimaryContainer.hasActivity(primaryActivity.getActivityToken())) {
+                mSecondaryContainer.addContainerToFinishOnExit(mPrimaryContainer);
+            } else {
+                // Only adding the activity to be finished vs. the entire TaskFragment while
+                // the secondary container exits because there are other unrelated activities in the
+                // primary TaskFragment.
+                mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
+            }
         }
-        if (mSplitPairRule.finishSecondaryWithPrimary || mSplitPairRule.useAsPlaceholder) {
+        if (shouldFinishSecondaryWithPrimary(splitRule)) {
             mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
         }
     }
@@ -56,7 +66,25 @@
     }
 
     @NonNull
-    ExtensionSplitPairRule getSplitPairRule() {
-        return mSplitPairRule;
+    SplitRule getSplitRule() {
+        return mSplitRule;
+    }
+
+    boolean isPlaceholderContainer() {
+        return (mSplitRule instanceof SplitPlaceholderRule);
+    }
+
+    static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
+        final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
+        final boolean shouldFinishPrimaryWithSecondary = (splitRule instanceof SplitPairRule)
+                && ((SplitPairRule) splitRule).shouldFinishPrimaryWithSecondary();
+        return shouldFinishPrimaryWithSecondary || isPlaceholderContainer;
+    }
+
+    static boolean shouldFinishSecondaryWithPrimary(@NonNull SplitRule splitRule) {
+        final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
+        final boolean shouldFinishSecondaryWithPrimary = (splitRule instanceof SplitPairRule)
+                && ((SplitPairRule) splitRule).shouldFinishSecondaryWithPrimary();
+        return shouldFinishSecondaryWithPrimary || isPlaceholderContainer;
     }
 }
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 a1ebb59..05c6792 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -24,7 +24,6 @@
 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;
@@ -32,20 +31,24 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.util.Pair;
 import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
 
-import androidx.window.extensions.ExtensionInterface.SplitOrganizerCallback;
-import androidx.window.extensions.ExtensionSplitActivityRule;
-import androidx.window.extensions.ExtensionSplitInfo;
-import androidx.window.extensions.ExtensionSplitPairRule;
-import androidx.window.extensions.ExtensionSplitRule;
-import androidx.window.extensions.ExtensionTaskFragment;
+import androidx.window.extensions.embedding.ActivityRule;
+import androidx.window.extensions.embedding.EmbeddingRule;
+import androidx.window.extensions.embedding.SplitInfo;
+import androidx.window.extensions.embedding.SplitPairRule;
+import androidx.window.extensions.embedding.SplitPlaceholderRule;
+import androidx.window.extensions.embedding.SplitRule;
+import androidx.window.extensions.embedding.TaskFragment;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Main controller class that manages split states and presentation.
@@ -55,12 +58,12 @@
     private final SplitPresenter mPresenter;
 
     // Currently applied split configuration.
-    private final List<ExtensionSplitRule> mSplitRules = new ArrayList<>();
+    private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
     private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
     private final List<SplitContainer> mSplitContainers = new ArrayList<>();
 
     // Callback to Jetpack to notify about changes to split states.
-    private SplitOrganizerCallback mSplitOrganizerCallback;
+    private @NonNull Consumer<List<SplitInfo>> mEmbeddingCallback;
 
     public SplitController() {
         mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
@@ -73,13 +76,14 @@
         instrumentation.addMonitor(new ActivityStartMonitor());
     }
 
-    public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
+    /** Updates the embedding rules applied to future activity launches. */
+    public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
         mSplitRules.clear();
-        mSplitRules.addAll(splitRules);
+        mSplitRules.addAll(rules);
     }
 
     @NonNull
-    public List<ExtensionSplitRule> getSplitRules() {
+    public List<EmbeddingRule> getSplitRules() {
         return mSplitRules;
     }
 
@@ -87,22 +91,20 @@
      * Starts an activity to side of the launchingActivity with the provided split config.
      */
     public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
-            @Nullable Bundle options, @NonNull ExtensionSplitPairRule splitPairRule,
-            int startRequestId) {
+            @Nullable Bundle options, @NonNull SplitRule sideRule,
+            @NonNull Consumer<Exception> failureCallback) {
         try {
-            mPresenter.startActivityToSide(launchingActivity, intent, options, splitPairRule);
+            mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule);
         } catch (Exception e) {
-            if (mSplitOrganizerCallback != null && startRequestId != -1) {
-                mSplitOrganizerCallback.onActivityFailedToStartInContainer(startRequestId, e);
-            }
+            failureCallback.accept(e);
         }
     }
 
     /**
      * Registers the split organizer callback to notify about changes to active splits.
      */
-    public void setSplitOrganizerCallback(@NonNull SplitOrganizerCallback callback) {
-        mSplitOrganizerCallback = callback;
+    public void setEmbeddingCallback(@NonNull Consumer<List<SplitInfo>> callback) {
+        mEmbeddingCallback = callback;
         updateCallbackIfNecessary();
     }
 
@@ -128,7 +130,7 @@
         // Check if there are no running activities - consider the container empty if there are no
         // non-finishing activities left.
         if (!taskFragmentInfo.hasRunningActivity()) {
-            cleanupContainer(container, true /* shouldFinishDependent */);
+            mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
             updateCallbackIfNecessary();
         }
     }
@@ -140,7 +142,7 @@
             return;
         }
 
-        cleanupContainer(container, true /* shouldFinishDependent */);
+        mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
         updateCallbackIfNecessary();
     }
 
@@ -160,14 +162,12 @@
      */
     // TODO(b/190433398): Break down into smaller functions.
     void onActivityCreated(@NonNull Activity launchedActivity) {
-        final ComponentName componentName = launchedActivity.getComponentName();
-
-        final List<ExtensionSplitRule> splitRules = getSplitRules();
+        final List<EmbeddingRule> splitRules = getSplitRules();
         final TaskFragmentContainer currentContainer = getContainerWithActivity(
                 launchedActivity.getActivityToken(), launchedActivity);
 
         // Check if the activity is configured to always be expanded.
-        if (shouldExpand(componentName, splitRules)) {
+        if (shouldExpand(launchedActivity, splitRules)) {
             if (shouldContainerBeExpanded(currentContainer)) {
                 // Make sure that the existing container is expanded
                 mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
@@ -224,8 +224,8 @@
             }
         }
 
-        final ExtensionSplitPairRule splitPairRule = getSplitRule(
-                activityBelow.getComponentName(), componentName, splitRules);
+        final SplitPairRule splitPairRule = getSplitRule(activityBelow, launchedActivity,
+                splitRules);
         if (splitPairRule == null) {
             return;
         }
@@ -270,7 +270,7 @@
     private TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken,
             Activity activityToAdd) {
         final IBinder taskFragmentToken = ActivityThread.currentActivityThread().getActivityClient(
-                activityToken).mTaskFragmentToken;
+                activityToken).mInitialTaskFragmentToken;
         for (TaskFragmentContainer container : mContainers) {
             if (container.hasActivity(activityToken)) {
                 return container;
@@ -296,24 +296,25 @@
     }
 
     /**
-     * Creates and registers a new split with the provided containers and configuration.
+     * Creates and registers a new split with the provided containers and configuration. Finishes
+     * existing secondary containers if found for the given primary container.
      */
-    void registerSplit(@NonNull TaskFragmentContainer primaryContainer,
-            @NonNull Activity primaryActivity,
+    void registerSplit(@NonNull WindowContainerTransaction wct,
+            @NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
             @NonNull TaskFragmentContainer secondaryContainer,
-            @NonNull ExtensionSplitPairRule splitPairRule) {
+            @NonNull SplitRule splitRule) {
+        if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
+            removeExistingSecondaryContainers(wct, primaryContainer);
+        }
         SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
-                secondaryContainer, splitPairRule);
+                secondaryContainer, splitRule);
         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<>();
@@ -324,8 +325,25 @@
             }
         }
         mSplitContainers.removeAll(containersToRemove);
+    }
 
-        mPresenter.deleteContainer(container);
+    /**
+     * Removes a secondary container for the given primary container if an existing split is
+     * already registered.
+     */
+    void removeExistingSecondaryContainers(@NonNull WindowContainerTransaction wct,
+            @NonNull TaskFragmentContainer primaryContainer) {
+        // If the primary container was already in a split - remove the secondary container that
+        // is now covered by the new one that replaced it.
+        final SplitContainer existingSplitContainer = getActiveSplitForContainer(
+                primaryContainer);
+        if (existingSplitContainer == null
+                || primaryContainer == existingSplitContainer.getSecondaryContainer()) {
+            return;
+        }
+
+        existingSplitContainer.getSecondaryContainer().finish(
+                false /* shouldFinishDependent */, mPresenter, wct, this);
     }
 
     /**
@@ -439,22 +457,20 @@
         }
 
         // Check if there is enough space for launch
-        final ExtensionSplitPairRule placeholderRule = getPlaceholderRule(
-                activity.getComponentName());
+        final SplitPlaceholderRule placeholderRule = getPlaceholderRule(activity);
         if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
                 mPresenter.getParentContainerBounds(activity), placeholderRule)) {
             return false;
         }
 
-        Intent placeholderIntent = new Intent();
-        placeholderIntent.setComponent(placeholderRule.secondaryActivityName);
         // TODO(b/190433398): Handle failed request
-        startActivityToSide(activity, placeholderIntent, null, placeholderRule, -1);
+        startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), null,
+                placeholderRule, null);
         return true;
     }
 
     private boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) {
-        if (!splitContainer.getSplitPairRule().useAsPlaceholder) {
+        if (!splitContainer.isPlaceholderContainer()) {
             return false;
         }
 
@@ -462,7 +478,7 @@
             return false;
         }
 
-        cleanupContainer(splitContainer.getSecondaryContainer(),
+        mPresenter.cleanupContainer(splitContainer.getSecondaryContainer(),
                 false /* shouldFinishDependent */);
         return true;
     }
@@ -471,15 +487,14 @@
      * Returns the rule to launch a placeholder for the activity with the provided component name
      * if it is configured in the split config.
      */
-    private ExtensionSplitPairRule getPlaceholderRule(@NonNull ComponentName componentName) {
-        for (ExtensionSplitRule rule : mSplitRules) {
-            if (!(rule instanceof ExtensionSplitPairRule)) {
+    private SplitPlaceholderRule getPlaceholderRule(@NonNull Activity activity) {
+        for (EmbeddingRule rule : mSplitRules) {
+            if (!(rule instanceof SplitPlaceholderRule)) {
                 continue;
             }
-            ExtensionSplitPairRule pairRule = (ExtensionSplitPairRule) rule;
-            if (componentName.equals(pairRule.primaryActivityName)
-                    && pairRule.useAsPlaceholder) {
-                return pairRule;
+            SplitPlaceholderRule placeholderRule = (SplitPlaceholderRule) rule;
+            if (placeholderRule.getActivityPredicate().test(activity)) {
+                return placeholderRule;
             }
         }
         return null;
@@ -489,27 +504,27 @@
      * Notifies listeners about changes to split states if necessary.
      */
     private void updateCallbackIfNecessary() {
-        if (mSplitOrganizerCallback == null) {
+        if (mEmbeddingCallback == null) {
             return;
         }
         // TODO(b/190433398): Check if something actually changed
-        mSplitOrganizerCallback.onSplitInfoChanged(getActiveSplitStates());
+        mEmbeddingCallback.accept(getActiveSplitStates());
     }
 
     /**
      * Returns a list of descriptors for currently active split states.
      */
-    private List<ExtensionSplitInfo> getActiveSplitStates() {
-        List<ExtensionSplitInfo> splitStates = new ArrayList<>();
+    private List<SplitInfo> getActiveSplitStates() {
+        List<SplitInfo> splitStates = new ArrayList<>();
         for (SplitContainer container : mSplitContainers) {
-            ExtensionTaskFragment primaryContainer =
-                    new ExtensionTaskFragment(
+            TaskFragment primaryContainer =
+                    new TaskFragment(
                             container.getPrimaryContainer().collectActivities());
-            ExtensionTaskFragment secondaryContainer =
-                    new ExtensionTaskFragment(
+            TaskFragment secondaryContainer =
+                    new TaskFragment(
                             container.getSecondaryContainer().collectActivities());
-            ExtensionSplitInfo splitState = new ExtensionSplitInfo(primaryContainer,
-                    secondaryContainer, container.getSplitPairRule().splitRatio);
+            SplitInfo splitState = new SplitInfo(primaryContainer,
+                    secondaryContainer, container.getSplitRule().getSplitRatio());
             splitStates.add(splitState);
         }
         return splitStates;
@@ -533,23 +548,41 @@
     }
 
     /**
-     * Returns a split rule for the provided pair of component names if available.
+     * Returns a split rule for the provided pair of primary activity and secondary activity intent
+     * if available.
      */
     @Nullable
-    private static ExtensionSplitPairRule getSplitRule(@NonNull ComponentName primaryActivityName,
-            @NonNull ComponentName secondaryActivityName,
-            @NonNull List<ExtensionSplitRule> splitRules) {
-        if (splitRules == null || primaryActivityName == null || secondaryActivityName == null) {
-            return null;
-        }
-
-        for (ExtensionSplitRule rule : splitRules) {
-            if (!(rule instanceof ExtensionSplitPairRule)) {
+    private static SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
+            @NonNull Intent secondaryActivityIntent, @NonNull List<EmbeddingRule> splitRules) {
+        for (EmbeddingRule rule : splitRules) {
+            if (!(rule instanceof SplitPairRule)) {
                 continue;
             }
-            ExtensionSplitPairRule pairRule = (ExtensionSplitPairRule) rule;
-            if (match(secondaryActivityName, pairRule.secondaryActivityName)
-                    && match(primaryActivityName, pairRule.primaryActivityName)) {
+            SplitPairRule pairRule = (SplitPairRule) rule;
+            if (pairRule.getActivityIntentPredicate().test(
+                    new Pair(primaryActivity, secondaryActivityIntent))) {
+                return pairRule;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a split rule for the provided pair of primary and secondary activities if available.
+     */
+    @Nullable
+    private static SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
+            @NonNull Activity secondaryActivity, @NonNull List<EmbeddingRule> splitRules) {
+        for (EmbeddingRule rule : splitRules) {
+            if (!(rule instanceof SplitPairRule)) {
+                continue;
+            }
+            SplitPairRule pairRule = (SplitPairRule) rule;
+            final Intent intent = secondaryActivity.getIntent();
+            if (pairRule.getActivityPairPredicate().test(
+                    new Pair(primaryActivity, secondaryActivity))
+                    && (intent == null || pairRule.getActivityIntentPredicate().test(
+                            new Pair(primaryActivity, intent)))) {
                 return pairRule;
             }
         }
@@ -570,55 +603,26 @@
      * Returns {@code true} if an Activity with the provided component name should always be
      * expanded to occupy full task bounds. Such activity must not be put in a split.
      */
-    private static boolean shouldExpand(@NonNull ComponentName componentName,
-            List<ExtensionSplitRule> splitRules) {
+    private static boolean shouldExpand(@NonNull Activity activity,
+            List<EmbeddingRule> splitRules) {
         if (splitRules == null) {
             return false;
         }
-        for (ExtensionSplitRule rule : splitRules) {
-            if (!(rule instanceof ExtensionSplitActivityRule)) {
+        for (EmbeddingRule rule : splitRules) {
+            if (!(rule instanceof ActivityRule)) {
                 continue;
             }
-            ExtensionSplitActivityRule activityRule = (ExtensionSplitActivityRule) rule;
-            if (match(componentName, activityRule.activityName)
-                    && activityRule.alwaysExpand) {
+            ActivityRule activityRule = (ActivityRule) rule;
+            if (!activityRule.shouldAlwaysExpand()) {
+                continue;
+            }
+            if (activityRule.getActivityPredicate().test(activity)) {
                 return true;
             }
         }
         return false;
     }
 
-    /** Match check allowing wildcards for activity class name but not package name. */
-    private static boolean match(@NonNull ComponentName activityComponent,
-            @NonNull ComponentName ruleComponent) {
-        if (activityComponent.toString().contains("*")) {
-            throw new IllegalArgumentException("Wildcard can only be part of the rule.");
-        }
-        final boolean packagesMatch =
-                activityComponent.getPackageName().equals(ruleComponent.getPackageName());
-        final boolean classesMatch =
-                activityComponent.getClassName().equals(ruleComponent.getClassName());
-        return packagesMatch && (classesMatch
-                || wildcardMatch(activityComponent.getClassName(), ruleComponent.getClassName()));
-    }
-
-    /**
-     * Checks if the provided name matches the pattern.
-     */
-    private static boolean wildcardMatch(@NonNull String name, @NonNull String pattern) {
-        if (!pattern.contains("*")) {
-            return false;
-        }
-        if (pattern.equals("*")) {
-            return true;
-        }
-        if (pattern.indexOf("*") != pattern.lastIndexOf("*") || !pattern.endsWith("*")) {
-            throw new IllegalArgumentException(
-                    "Name pattern with a wildcard must only contain a single * in the end");
-        }
-        return name.startsWith(pattern.substring(0, pattern.length() - 1));
-    }
-
     private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {
 
         @Override
@@ -681,8 +685,8 @@
     private class ActivityStartMonitor extends Instrumentation.ActivityMonitor {
 
         @Override
-        public Instrumentation.ActivityResult onStartActivity(Context who, Intent intent,
-                Bundle options) {
+        public Instrumentation.ActivityResult onStartActivity(@NonNull Context who,
+                @NonNull Intent intent, @NonNull 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.
@@ -691,10 +695,24 @@
             }
             final Activity launchingActivity = (Activity) who;
 
-            final ExtensionSplitPairRule splitPairRule = getSplitRule(
-                    launchingActivity.getComponentName(), intent.getComponent(), getSplitRules());
+            if (!setLaunchingToSideContainer(launchingActivity, intent, options)) {
+                setLaunchingInSameContainer(launchingActivity, intent, options);
+            }
+
+            return super.onStartActivity(who, intent, options);
+        }
+
+        /**
+         * Returns {@code true} if the activity that is going to be started via the
+         * {@code intent} should be paired with the {@code launchingActivity} and is set to be
+         * launched in an empty side container.
+         */
+        private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent,
+                Bundle options) {
+            final SplitPairRule splitPairRule = getSplitRule(launchingActivity, intent,
+                    getSplitRules());
             if (splitPairRule == null) {
-                return super.onStartActivity(who, intent, options);
+                return false;
             }
 
             // Create a new split with an empty side container
@@ -705,8 +723,52 @@
             // dedicated container.
             options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
                     secondaryContainer.getTaskFragmentToken());
+            return true;
+        }
 
-            return super.onStartActivity(who, intent, options);
+        /**
+         * Checks if the activity that is going to be started via the {@code intent} should be
+         * paired with the existing top activity which is currently paired with the
+         * {@code launchingActivity}. If so, set the activity to be launched in the same
+         * container of the {@code launchingActivity}.
+         */
+        private void setLaunchingInSameContainer(Activity launchingActivity, Intent intent,
+                Bundle options) {
+            final TaskFragmentContainer launchingContainer = getContainerWithActivity(
+                    launchingActivity.getActivityToken());
+            if (launchingContainer == null) {
+                return;
+            }
+
+            final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer);
+            if (splitContainer == null) {
+                return;
+            }
+
+            if (splitContainer.getSecondaryContainer() != launchingContainer) {
+                return;
+            }
+
+            // The launching activity is on the secondary container. Retrieve the primary
+            // activity from the other container.
+            Activity primaryActivity =
+                    splitContainer.getPrimaryContainer().getTopNonFinishingActivity();
+            if (primaryActivity == null) {
+                return;
+            }
+
+            final SplitPairRule splitPairRule = getSplitRule(primaryActivity, intent,
+                    getSplitRules());
+            if (splitPairRule == null) {
+                return;
+            }
+
+            // Amend the request to let the WM know that the activity should be placed in the
+            // dedicated container. This is necessary for the case that the activity is started
+            // into a new Task, or new Task will be escaped from the current host Task and be
+            // displayed in fullscreen.
+            options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
+                    launchingContainer.getTaskFragmentToken());
         }
     }
 }
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 d8b1d2a..ac85ac8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
@@ -24,13 +24,16 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.view.WindowInsets;
+import android.view.WindowMetrics;
 import android.window.TaskFragmentCreationParams;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.window.extensions.ExtensionSplitPairRule;
+import androidx.window.extensions.embedding.SplitPairRule;
+import androidx.window.extensions.embedding.SplitRule;
 
 import java.util.concurrent.Executor;
 
@@ -68,11 +71,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) {
@@ -87,7 +92,7 @@
      * @return The newly created secondary container.
      */
     TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
-            @NonNull ExtensionSplitPairRule rule) {
+            @NonNull SplitPairRule rule) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         final Rect parentBounds = getParentContainerBounds(primaryActivity);
@@ -104,11 +109,12 @@
         secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
 
         // Set adjacent to each other so that the containers below will be invisible.
-        wct.setAdjacentTaskFragments(
-                primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
-        applyTransaction(wct);
+        setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
+                secondaryContainer.getTaskFragmentToken(), rule);
 
-        mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+        mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
+
+        applyTransaction(wct);
 
         return secondaryContainer;
     }
@@ -125,7 +131,7 @@
      * @param rule The split rule to be applied to the container.
      */
     void createNewSplitContainer(@NonNull Activity primaryActivity,
-            @NonNull Activity secondaryActivity, @NonNull ExtensionSplitPairRule rule) {
+            @NonNull Activity secondaryActivity, @NonNull SplitPairRule rule) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         final Rect parentBounds = getParentContainerBounds(primaryActivity);
@@ -138,11 +144,12 @@
                 secondaryActivity, secondaryRectBounds, primaryContainer);
 
         // Set adjacent to each other so that the containers below will be invisible.
-        wct.setAdjacentTaskFragments(
-                primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
-        applyTransaction(wct);
+        setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
+                secondaryContainer.getTaskFragmentToken(), rule);
 
-        mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+        mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
+
+        applyTransaction(wct);
     }
 
     /**
@@ -188,7 +195,7 @@
      * @param rule The split rule to be applied to the container.
      */
     void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
-            @Nullable Bundle activityOptions, @NonNull ExtensionSplitPairRule rule) {
+            @Nullable Bundle activityOptions, @NonNull SplitRule rule) {
         final Rect parentBounds = getParentContainerBounds(launchingActivity);
         final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
         final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
@@ -200,20 +207,16 @@
         }
 
         TaskFragmentContainer secondaryContainer = mController.newContainer(null);
-        startActivityToSide(
-                primaryContainer.getTaskFragmentToken(),
-                primaryRectBounds,
-                launchingActivity,
-                secondaryContainer.getTaskFragmentToken(),
-                secondaryRectBounds,
-                activityIntent,
-                activityOptions);
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
+                rule);
+        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
+                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds,
+                activityIntent, activityOptions, rule);
+        applyTransaction(wct);
 
         primaryContainer.setLastRequestedBounds(primaryRectBounds);
         secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
-
-        mController.registerSplit(primaryContainer, launchingActivity, secondaryContainer,
-                rule);
     }
 
     /**
@@ -227,7 +230,7 @@
             @NonNull WindowContainerTransaction wct) {
         // Getting the parent bounds using the updated container - it will have the recent value.
         final Rect parentBounds = getParentContainerBounds(updatedContainer);
-        final ExtensionSplitPairRule rule = splitContainer.getSplitPairRule();
+        final SplitRule rule = splitContainer.getSplitRule();
         final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
         final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
 
@@ -273,24 +276,24 @@
 
     boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
         final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
-        return shouldShowSideBySide(parentBounds, splitContainer.getSplitPairRule());
+        return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule());
     }
 
-    boolean shouldShowSideBySide(@Nullable Rect parentBounds,
-            @NonNull ExtensionSplitPairRule rule) {
-        return parentBounds != null && parentBounds.width() >= rule.minWidth
-                // TODO(b/190433398): Consider proper smallest width computation.
-                && Math.min(parentBounds.width(), parentBounds.height()) >= rule.minSmallestWidth;
+    boolean shouldShowSideBySide(@Nullable Rect parentBounds, @NonNull SplitRule rule) {
+        // TODO(b/190433398): Supply correct insets.
+        final WindowMetrics parentMetrics = new WindowMetrics(parentBounds,
+                new WindowInsets(new Rect()));
+        return rule.getParentWindowMetricsPredicate().test(parentMetrics);
     }
 
     @NonNull
     private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
-            @NonNull ExtensionSplitPairRule rule) {
+            @NonNull SplitRule rule) {
         if (!shouldShowSideBySide(parentBounds, rule)) {
             return new Rect();
         }
 
-        float splitRatio = rule.splitRatio;
+        float splitRatio = rule.getSplitRatio();
         switch (position) {
             case POSITION_LEFT:
                 return new Rect(
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
new file mode 100644
index 0000000..b85287d
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
@@ -0,0 +1,61 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+
+import android.util.Log;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.window.TaskFragmentOrganizer;
+
+/** Controls the TaskFragment remote animations. */
+class TaskFragmentAnimationController {
+
+    private static final String TAG = "TaskFragAnimationCtrl";
+    // TODO(b/196173550) turn off when finalize
+    static final boolean DEBUG = false;
+
+    private final TaskFragmentOrganizer mOrganizer;
+    private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
+
+    TaskFragmentAnimationController(TaskFragmentOrganizer organizer) {
+        mOrganizer = organizer;
+    }
+
+    void registerRemoteAnimations() {
+        if (DEBUG) {
+            Log.v(TAG, "registerRemoteAnimations");
+        }
+        final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+        final RemoteAnimationAdapter animationAdapter =
+                new RemoteAnimationAdapter(mRemoteRunner, 0, 0);
+        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
+        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
+        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
+        mOrganizer.registerRemoteAnimations(definition);
+    }
+
+    void unregisterRemoteAnimations() {
+        if (DEBUG) {
+            Log.v(TAG, "unregisterRemoteAnimations");
+        }
+        mOrganizer.unregisterRemoteAnimations();
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
new file mode 100644
index 0000000..9ee60d8
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
@@ -0,0 +1,93 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import androidx.annotation.Nullable;
+
+/** To run the TaskFragment animations. */
+class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
+
+    private static final String TAG = "TaskFragAnimationRunner";
+    private final Handler mHandler = new Handler(Looper.myLooper());
+
+    @Nullable
+    private IRemoteAnimationFinishedCallback mFinishedCallback;
+
+    @Override
+    public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+            RemoteAnimationTarget[] apps,
+            RemoteAnimationTarget[] wallpapers,
+            RemoteAnimationTarget[] nonApps,
+            IRemoteAnimationFinishedCallback finishedCallback) {
+        if (wallpapers.length != 0 || nonApps.length != 0) {
+            throw new IllegalArgumentException("TaskFragment shouldn't handle animation with"
+                    + "wallpaper or non-app windows.");
+        }
+        if (TaskFragmentAnimationController.DEBUG) {
+            Log.v(TAG, "onAnimationStart transit=" + transit);
+        }
+        mHandler.post(() -> startAnimation(apps, finishedCallback));
+    }
+
+    @Override
+    public void onAnimationCancelled() {
+        if (TaskFragmentAnimationController.DEBUG) {
+            Log.v(TAG, "onAnimationCancelled");
+        }
+        mHandler.post(this::onAnimationFinished);
+    }
+
+    private void startAnimation(RemoteAnimationTarget[] targets,
+            IRemoteAnimationFinishedCallback finishedCallback) {
+        // TODO(b/196173550) replace with actual animations
+        mFinishedCallback = finishedCallback;
+        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        for (RemoteAnimationTarget target : targets) {
+            if (target.mode == MODE_OPENING) {
+                t.show(target.leash);
+                t.setAlpha(target.leash, 1);
+            }
+            t.setPosition(target.leash, target.localBounds.left, target.localBounds.top);
+        }
+        t.apply();
+        onAnimationFinished();
+    }
+
+    private void onAnimationFinished() {
+        if (mFinishedCallback == null) {
+            return;
+        }
+        try {
+            mFinishedCallback.onAnimationFinished();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        mFinishedCallback = null;
+    }
+}
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 f47dc24..a9155cf 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;
@@ -124,6 +125,14 @@
         return false;
     }
 
+    int getRunningActivityCount() {
+        int count = mPendingAppearedActivities.size();
+        if (mInfo != null) {
+            count += mInfo.getRunningActivityCount();
+        }
+        return count;
+    }
+
     @Nullable
     TaskFragmentInfo getInfo() {
         return mInfo;
@@ -179,7 +188,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;
         }
@@ -190,13 +200,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();
 
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index fdbc5f6..097febf 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml b/libs/WindowManager/Shell/res/color/split_divider_background.xml
similarity index 65%
copy from packages/SystemUI/res/values-h560dp-xhdpi/config.xml
copy to libs/WindowManager/Shell/res/color/split_divider_background.xml
index cf2017f..84f4fdf 100644
--- a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml
+++ b/libs/WindowManager/Shell/res/color/split_divider_background.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2014 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,11 +12,8 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT 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.
   -->
-<resources>
-    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
-     card. -->
-    <integer name="keyguard_max_notification_count">3</integer>
-</resources>
-
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_bottom.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_bottom.xml
new file mode 100644
index 0000000..18dc909
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_bottom.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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="@dimen/split_divider_corner_size"
+        android:height="@dimen/split_divider_corner_size"
+        android:viewportWidth="42"
+        android:viewportHeight="42">
+
+    <group android:pivotX="21"
+           android:pivotY="21"
+           android:rotation="180">
+        <path
+            android:fillColor="@color/split_divider_background"
+            android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_left.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_left.xml
new file mode 100644
index 0000000..931cacf
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_left.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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="@dimen/split_divider_corner_size"
+        android:height="@dimen/split_divider_corner_size"
+        android:viewportWidth="42"
+        android:viewportHeight="42">
+
+    <group android:pivotX="21"
+           android:pivotY="21"
+           android:rotation="-90">
+        <path
+            android:fillColor="@color/split_divider_background"
+            android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_right.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_right.xml
new file mode 100644
index 0000000..54e4761
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_right.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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="@dimen/split_divider_corner_size"
+        android:height="@dimen/split_divider_corner_size"
+        android:viewportWidth="42"
+        android:viewportHeight="42">
+
+    <group android:pivotX="21"
+           android:pivotY="21"
+           android:rotation="90">
+        <path
+            android:fillColor="@color/split_divider_background"
+            android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_top.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_top.xml
new file mode 100644
index 0000000..9115b5a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_top.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="@dimen/split_divider_corner_size"
+        android:height="@dimen/split_divider_corner_size"
+        android:viewportWidth="42"
+        android:viewportHeight="42">
+
+    <path
+        android:fillColor="@color/split_divider_background"
+        android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
index 7658fca..0cf6d73 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
@@ -17,7 +17,7 @@
 <com.android.wm.shell.common.AlphaOptimizedButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@android:style/Widget.DeviceDefault.Button.Borderless"
-    android:id="@+id/settings_button"
+    android:id="@+id/manage_button"
     android:layout_gravity="start"
     android:layout_width="wrap_content"
     android:layout_height="@dimen/bubble_manage_button_height"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
index fd4c3ba..87deb8b 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
@@ -21,7 +21,6 @@
     android:layout_width="wrap_content"
     android:paddingTop="48dp"
     android:paddingBottom="48dp"
-    android:paddingStart="@dimen/bubble_stack_user_education_side_inset"
     android:paddingEnd="16dp"
     android:layout_marginEnd="24dp"
     android:orientation="vertical"
diff --git a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
index c5c42fc..fafe40e 100644
--- a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
@@ -23,7 +23,6 @@
     android:clickable="true"
     android:paddingTop="28dp"
     android:paddingBottom="16dp"
-    android:paddingStart="@dimen/bubble_expanded_view_padding"
     android:paddingEnd="48dp"
     android:layout_marginEnd="24dp"
     android:orientation="vertical"
@@ -66,27 +65,21 @@
         android:id="@+id/button_layout"
         android:orientation="horizontal" >
 
-        <com.android.wm.shell.common.AlphaOptimizedButton
-            style="@android:style/Widget.Material.Button.Borderless"
-            android:id="@+id/manage"
-            android:layout_gravity="start"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:focusable="true"
-            android:clickable="false"
-            android:text="@string/manage_bubbles_text"
-            android:textColor="@android:color/system_neutral1_900"
+        <include
+            layout="@layout/bubble_manage_button"
             />
 
         <com.android.wm.shell.common.AlphaOptimizedButton
-            style="@android:style/Widget.Material.Button.Borderless"
+            style="@android:style/Widget.DeviceDefault.Button.Borderless"
             android:id="@+id/got_it"
             android:layout_gravity="start"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="@dimen/bubble_manage_button_height"
             android:focusable="true"
             android:text="@string/bubbles_user_education_got_it"
+            android:textSize="@*android:dimen/text_size_body_2_material"
             android:textColor="@android:color/system_neutral1_900"
+            android:background="@drawable/bubble_manage_btn_bg"
             />
     </LinearLayout>
 </LinearLayout>
diff --git a/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
index ed5d2e1..d732b01 100644
--- a/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
@@ -22,7 +22,7 @@
     <View
         style="@style/DockedDividerBackground"
         android:id="@+id/docked_divider_background"
-        android:background="@color/docked_divider_background"/>
+        android:background="@color/split_divider_background"/>
 
     <com.android.wm.shell.legacysplitscreen.MinimizedDockShadow
         style="@style/DockedDividerMinimizedShadow"
diff --git a/libs/WindowManager/Shell/res/layout/split_divider.xml b/libs/WindowManager/Shell/res/layout/split_divider.xml
index 7f583f3..94182cd 100644
--- a/libs/WindowManager/Shell/res/layout/split_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/split_divider.xml
@@ -19,15 +19,25 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
-    <View
-        style="@style/DockedDividerBackground"
-        android:id="@+id/docked_divider_background"
-        android:background="@color/docked_divider_background"/>
+    <FrameLayout
+        android:id="@+id/divider_bar"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
 
-    <com.android.wm.shell.common.split.DividerHandleView
-        style="@style/DockedDividerHandle"
-        android:id="@+id/docked_divider_handle"
-        android:contentDescription="@string/accessibility_divider"
-        android:background="@null"/>
+        <View style="@style/DockedDividerTopLeftRoundCorner"/>
+
+        <View
+            style="@style/DockedDividerBackground"
+            android:id="@+id/docked_divider_background"/>
+
+        <View style="@style/DockedDividerBottomRightRoundCorner"/>
+
+        <com.android.wm.shell.common.split.DividerHandleView
+            style="@style/DockedDividerHandle"
+            android:id="@+id/docked_divider_handle"
+            android:contentDescription="@string/accessibility_divider"
+            android:background="@null"/>
+
+    </FrameLayout>
 
 </com.android.wm.shell.common.split.DividerView>
diff --git a/libs/WindowManager/Shell/res/values-land/dimens.xml b/libs/WindowManager/Shell/res/values-land/dimens.xml
index aafba58..a95323f 100644
--- a/libs/WindowManager/Shell/res/values-land/dimens.xml
+++ b/libs/WindowManager/Shell/res/values-land/dimens.xml
@@ -16,8 +16,12 @@
 */
 -->
 <resources>
+    <!-- Divider handle size for legacy split screen -->
     <dimen name="docked_divider_handle_width">2dp</dimen>
     <dimen name="docked_divider_handle_height">16dp</dimen>
+    <!-- Divider handle size for split screen -->
+    <dimen name="split_divider_handle_width">3dp</dimen>
+    <dimen name="split_divider_handle_height">72dp</dimen>
 
     <!-- Padding between status bar and bubbles when displayed in expanded state, smaller
      value in landscape since we have limited vertical space-->
diff --git a/libs/WindowManager/Shell/res/values-land/styles.xml b/libs/WindowManager/Shell/res/values-land/styles.xml
index 863bb69..e5707f3 100644
--- a/libs/WindowManager/Shell/res/values-land/styles.xml
+++ b/libs/WindowManager/Shell/res/values-land/styles.xml
@@ -19,6 +19,7 @@
         <item name="android:layout_width">10dp</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:layout_gravity">center_horizontal</item>
+        <item name="android:background">@color/split_divider_background</item>
     </style>
 
     <style name="DockedDividerHandle">
@@ -27,6 +28,20 @@
         <item name="android:layout_height">96dp</item>
     </style>
 
+    <style name="DockedDividerTopLeftRoundCorner">
+        <item name="android:layout_gravity">center_horizontal|top</item>
+        <item name="android:background">@drawable/split_rounded_top</item>
+        <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+        <item name="android:layout_height">@dimen/split_divider_corner_size</item>
+    </style>
+
+    <style name="DockedDividerBottomRightRoundCorner">
+        <item name="android:layout_gravity">center_horizontal|bottom</item>
+        <item name="android:background">@drawable/split_rounded_bottom</item>
+        <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+        <item name="android:layout_height">@dimen/split_divider_corner_size</item>
+    </style>
+
     <style name="DockedDividerMinimizedShadow">
         <item name="android:layout_width">8dp</item>
         <item name="android:layout_height">match_parent</item>
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/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 350beaf..93c0352 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,7 +17,6 @@
  */
 -->
 <resources>
-    <color name="docked_divider_background">#ff000000</color>
     <color name="docked_divider_handle">#ffffff</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
     <color name="minimize_dock_shadow_start">#60000000</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 7da31aa..f8576643 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -76,8 +76,15 @@
     <!-- How high we lift the divider when touching -->
     <dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
 
+    <!-- Divider handle size for legacy split screen -->
     <dimen name="docked_divider_handle_width">16dp</dimen>
     <dimen name="docked_divider_handle_height">2dp</dimen>
+    <!-- Divider handle size for split screen -->
+    <dimen name="split_divider_handle_width">72dp</dimen>
+    <dimen name="split_divider_handle_height">3dp</dimen>
+
+    <dimen name="split_divider_bar_width">10dp</dimen>
+    <dimen name="split_divider_corner_size">42dp</dimen>
 
     <!-- One-Handed Mode -->
     <!-- Threshold for dragging distance to enable one-handed mode -->
@@ -124,7 +131,7 @@
          should also be updated. -->
     <dimen name="bubble_expanded_default_height">180dp</dimen>
     <!-- On large screens the width of the expanded view is restricted to this size. -->
-    <dimen name="bubble_expanded_view_tablet_width">412dp</dimen>
+    <dimen name="bubble_expanded_view_phone_landscape_overflow_width">412dp</dimen>
     <!-- Inset to apply to the icon in the overflow button. -->
     <dimen name="bubble_overflow_icon_inset">30dp</dimen>
     <!-- Default (and minimum) height of bubble overflow -->
@@ -184,14 +191,8 @@
     <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
     <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
     <dimen name="bubble_manage_menu_elevation">4dp</dimen>
-
-    <!-- Bubbles user education views -->
-    <dimen name="bubbles_manage_education_width">160dp</dimen>
-    <!-- The inset from the top bound of the manage button to place the user education. -->
-    <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
-    <!-- Size of padding for the user education cling, this should at minimum be larger than
-        individual_bubble_size + some padding. -->
-    <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
+    <!-- Size of user education views on large screens (phone is just match parent). -->
+    <dimen name="bubbles_user_education_width_large_screen">400dp</dimen>
 
     <!-- The width/height of the size compat restart button. -->
     <dimen name="size_compat_button_size">48dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index fffcd33..28ff25a 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -32,8 +32,23 @@
 
     <style name="DockedDividerBackground">
         <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">10dp</item>
+        <item name="android:layout_height">@dimen/split_divider_bar_width</item>
         <item name="android:layout_gravity">center_vertical</item>
+        <item name="android:background">@color/split_divider_background</item>
+    </style>
+
+    <style name="DockedDividerTopLeftRoundCorner">
+        <item name="android:layout_gravity">center_vertical|left</item>
+        <item name="android:background">@drawable/split_rounded_left</item>
+        <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+        <item name="android:layout_height">@dimen/split_divider_corner_size</item>
+    </style>
+
+    <style name="DockedDividerBottomRightRoundCorner">
+        <item name="android:layout_gravity">center_vertical|right</item>
+        <item name="android:background">@drawable/split_rounded_right</item>
+        <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+        <item name="android:layout_height">@dimen/split_divider_corner_size</item>
     </style>
 
     <style name="DockedDividerMinimizedShadow">
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..df4f238 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -20,10 +20,13 @@
 
 import com.android.wm.shell.apppairs.AppPairsController;
 import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 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;
@@ -38,7 +41,9 @@
 public class ShellInitImpl {
     private static final String TAG = ShellInitImpl.class.getSimpleName();
 
+    private final DisplayController mDisplayController;
     private final DisplayImeController mDisplayImeController;
+    private final DisplayInsetsController mDisplayInsetsController;
     private final DragAndDropController mDragAndDropController;
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final Optional<BubbleController> mBubblesOptional;
@@ -47,13 +52,17 @@
     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;
 
     private final InitImpl mImpl = new InitImpl();
 
-    public ShellInitImpl(DisplayImeController displayImeController,
+    public ShellInitImpl(
+            DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<BubbleController> bubblesOptional,
@@ -62,10 +71,13 @@
             Optional<AppPairsController> appPairsOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
             Transitions transitions,
             StartingWindowController startingWindow,
             ShellExecutor mainExecutor) {
+        mDisplayController = displayController;
         mDisplayImeController = displayImeController;
+        mDisplayInsetsController = displayInsetsController;
         mDragAndDropController = dragAndDropController;
         mShellTaskOrganizer = shellTaskOrganizer;
         mBubblesOptional = bubblesOptional;
@@ -74,6 +86,7 @@
         mAppPairsOptional = appPairsOptional;
         mFullscreenTaskListener = fullscreenTaskListener;
         mPipTouchHandlerOptional = pipTouchHandlerOptional;
+        mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
         mTransitions = transitions;
         mMainExecutor = mainExecutor;
         mStartingWindow = startingWindow;
@@ -84,7 +97,9 @@
     }
 
     private void init() {
-        // Start listening for display changes
+        // Start listening for display and insets changes
+        mDisplayController.initialize();
+        mDisplayInsetsController.initialize();
         mDisplayImeController.startMonitorDisplays();
 
         // Setup the shell organizer
@@ -108,6 +123,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..b5dffba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -31,6 +31,7 @@
 import android.app.TaskInfo;
 import android.content.Context;
 import android.content.LocusId;
+import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
@@ -46,6 +47,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.wm.shell.common.ScreenshotUtils;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
@@ -71,12 +73,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 {}
 
@@ -486,14 +490,40 @@
     }
 
     @Override
+    public void onSizeCompatRestartButtonAppeared(int taskId) {
+        final TaskAppearedInfo info;
+        synchronized (mLock) {
+            info = mTasks.get(taskId);
+        }
+        if (info == null) {
+            return;
+        }
+        logSizeCompatRestartButtonEventReported(info,
+                FrameworkStatsLog.SIZE_COMPAT_RESTART_BUTTON_EVENT_REPORTED__EVENT__APPEARED);
+    }
+
+    @Override
     public void onSizeCompatRestartButtonClicked(int taskId) {
         final TaskAppearedInfo info;
         synchronized (mLock) {
             info = mTasks.get(taskId);
         }
-        if (info != null) {
-            restartTaskTopActivityProcessIfVisible(info.getTaskInfo().token);
+        if (info == null) {
+            return;
         }
+        logSizeCompatRestartButtonEventReported(info,
+                FrameworkStatsLog.SIZE_COMPAT_RESTART_BUTTON_EVENT_REPORTED__EVENT__CLICKED);
+        restartTaskTopActivityProcessIfVisible(info.getTaskInfo().token);
+    }
+
+    private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info,
+            int event) {
+        ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo;
+        if (topActivityInfo == null) {
+            return;
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.SIZE_COMPAT_RESTART_BUTTON_EVENT_REPORTED,
+                topActivityInfo.applicationInfo.uid, event);
     }
 
     /**
@@ -572,6 +602,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 +617,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 8405385..3800b8d 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
@@ -19,6 +19,7 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
 
 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;
@@ -181,7 +182,7 @@
 
         // TODO: Is there more we need to do here?
         mSyncQueue.runInSync(t -> {
-            t.setLayer(dividerLeash, Integer.MAX_VALUE)
+            t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER)
                     .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
                             mTaskInfo1.positionInParent.y)
                     .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
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 e7764ea..9dafefe 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
@@ -628,18 +628,27 @@
             mAddedToWindowManager = true;
             mBubbleData.getOverflow().initialize(this);
             mWindowManager.addView(mStackView, mWmLayoutParams);
-            // Position info is dependent on us being attached to a window
-            mBubblePositioner.update();
+            mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
+                mBubblePositioner.update();
+                mStackView.onDisplaySizeChanged();
+                return windowInsets;
+            });
         } catch (IllegalStateException e) {
             // This means the stack has already been added. This shouldn't happen...
             e.printStackTrace();
         }
     }
 
-    /** For the overflow to be focusable & receive key events the flags must be update. **/
-    void updateWindowFlagsForOverflow(boolean showingOverflow) {
+    /**
+     * In some situations bubble's should be able to receive key events for back:
+     * - when the bubble overflow is showing
+     * - when the user education for the stack is showing.
+     *
+     * @param interceptBack whether back should be intercepted or not.
+     */
+    void updateWindowFlagsForBackpress(boolean interceptBack) {
         if (mStackView != null && mAddedToWindowManager) {
-            mWmLayoutParams.flags = showingOverflow
+            mWmLayoutParams.flags = interceptBack
                     ? 0
                     : WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index d73ce69..b48bda3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -699,10 +699,9 @@
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "setSelectedBubbleInternal: " + bubble);
         }
-        if (!mShowingOverflow && Objects.equals(bubble, mSelectedBubble)) {
+        if (Objects.equals(bubble, mSelectedBubble)) {
             return;
         }
-        // Otherwise, if we are showing the overflow menu, return to the previously selected bubble.
         boolean isOverflow = bubble != null && BubbleOverflow.KEY.equals(bubble.getKey());
         if (bubble != null
                 && !mBubbles.contains(bubble)
@@ -771,6 +770,10 @@
                 Log.e(TAG, "Attempt to expand stack without selected bubble!");
                 return;
             }
+            if (mSelectedBubble.getKey().equals(mOverflow.getKey()) && !mBubbles.isEmpty()) {
+                // Show previously selected bubble instead of overflow menu when expanding.
+                setSelectedBubbleInternal(mBubbles.get(0));
+            }
             if (mSelectedBubble instanceof Bubble) {
                 ((Bubble) mSelectedBubble).markAsAccessedAt(mTimeSource.currentTimeMillis());
             }
@@ -779,16 +782,6 @@
             // Apply ordering and grouping rules from expanded -> collapsed, then save
             // the result.
             mStateChange.orderChanged |= repackAll();
-            // Save the state which should be returned to when expanded (with no other changes)
-
-            if (mShowingOverflow) {
-                // Show previously selected bubble instead of overflow menu on next expansion.
-                if (!mSelectedBubble.getKey().equals(mOverflow.getKey())) {
-                    setSelectedBubbleInternal(mSelectedBubble);
-                } else {
-                    setSelectedBubbleInternal(mBubbles.get(0));
-                }
-            }
             if (mBubbles.indexOf(mSelectedBubble) > 0) {
                 // Move the selected bubble to the top while collapsed.
                 int index = mBubbles.indexOf(mSelectedBubble);
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 252b588..7d7bfb2 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
@@ -228,7 +228,7 @@
         @Override
         public void onBackPressedOnTaskRoot(int taskId) {
             if (mTaskId == taskId && mStackView.isExpanded()) {
-                mController.collapseStack();
+                mStackView.onBackPressed();
             }
         }
     };
@@ -696,8 +696,10 @@
                 ? mPointerHeight - mPointerOverlap
                 : 0;
         final float paddingRight = (showVertically && !onLeft)
-                ? mPointerHeight - mPointerOverlap : 0;
-        final float paddingTop = showVertically ? 0
+                ? mPointerHeight - mPointerOverlap
+                : 0;
+        final float paddingTop = showVertically
+                ? 0
                 : mPointerHeight - mPointerOverlap;
         setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index ede4228..5e9d97f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -142,7 +142,7 @@
         super.onAttachedToWindow();
         if (mController != null) {
             // For the overflow to get key events (e.g. back press) we need to adjust the flags
-            mController.updateWindowFlagsForOverflow(true);
+            mController.updateWindowFlagsForBackpress(true);
         }
         setOnKeyListener(mKeyListener);
     }
@@ -151,7 +151,7 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         if (mController != null) {
-            mController.updateWindowFlagsForOverflow(false);
+            mController.updateWindowFlagsForBackpress(false);
         }
         setOnKeyListener(null);
     }
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 df804ec..306224b 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
@@ -65,7 +65,8 @@
     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;
-
+    /** The percent of screen width that should be used for the expanded view on a large screen. **/
+    public static final float EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT = 0.72f;
 
     private Context mContext;
     private WindowManager mWindowManager;
@@ -78,13 +79,18 @@
 
     private int mBubbleSize;
     private int mSpacingBetweenBubbles;
+
+    private int mExpandedViewMinHeight;
     private int mExpandedViewLargeScreenWidth;
+    private int mExpandedViewLargeScreenInset;
+
+    private int mOverflowWidth;
     private int mExpandedViewPadding;
     private int mPointerMargin;
     private int mPointerWidth;
     private int mPointerHeight;
+    private int mPointerOverlap;
     private int mManageButtonHeight;
-    private int mExpandedViewMinHeight;
     private int mOverflowHeight;
     private int mMinimumFlyoutWidthLargeScreen;
 
@@ -166,13 +172,20 @@
         mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
         mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
         mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
-
-        mExpandedViewLargeScreenWidth = res.getDimensionPixelSize(
-                R.dimen.bubble_expanded_view_tablet_width);
         mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
+        mExpandedViewLargeScreenWidth = (int) (bounds.width()
+                * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT);
+        mExpandedViewLargeScreenInset = mIsLargeScreen
+                ? (bounds.width() - mExpandedViewLargeScreenWidth) / 2
+                : mExpandedViewPadding;
+        mOverflowWidth = mIsLargeScreen
+                ? mExpandedViewLargeScreenWidth
+                : res.getDimensionPixelSize(
+                        R.dimen.bubble_expanded_view_phone_landscape_overflow_width);
         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_total_height);
         mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
         mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
@@ -242,6 +255,13 @@
     }
 
     /**
+     * @return a rect of the screen size.
+     */
+    public Rect getScreenRect() {
+        return mScreenRect;
+    }
+
+    /**
      * @return the relevant insets (status bar, nav bar, cutouts). If taskbar is showing, its
      * inset is not included here.
      */
@@ -283,63 +303,93 @@
     }
 
     /**
-     * Calculates the left & right padding for the bubble expanded view.
+     * Calculates the padding for the bubble expanded view.
      *
-     * On larger screens the width of the expanded view is restricted via this padding.
-     * On landscape the bubble overflow expanded view is also restricted via this padding.
+     * Some specifics:
+     * On large screens the width of the expanded view is restricted via this padding.
+     * On phone landscape the bubble overflow expanded view is also restricted via this padding.
+     * On large screens & landscape no top padding is set, the top position is set via translation.
+     * On phone portrait top padding is set as the space between the tip of the pointer and the
+     * bubble.
+     * When the overflow is shown it doesn't have the manage button to pad out the bottom so
+     * padding is added.
      */
-    public int[] getExpandedViewPadding(boolean onLeft, boolean isOverflow) {
-        int leftPadding = mInsets.left + mExpandedViewPadding;
-        int rightPadding = mInsets.right + mExpandedViewPadding;
-        final boolean isLargeOrOverflow = mIsLargeScreen || isOverflow;
-        if (showBubblesVertically()) {
-            if (!onLeft) {
-                rightPadding += mBubbleSize - mPointerHeight;
-                leftPadding += isLargeOrOverflow
-                        ? (mPositionRect.width() - rightPadding - mExpandedViewLargeScreenWidth)
-                        : 0;
-            } else {
-                leftPadding += mBubbleSize - mPointerHeight;
-                rightPadding += isLargeOrOverflow
-                        ? (mPositionRect.width() - leftPadding - mExpandedViewLargeScreenWidth)
-                        : 0;
+    public int[] getExpandedViewContainerPadding(boolean onLeft, boolean isOverflow) {
+        final int pointerTotalHeight = mPointerHeight - mPointerOverlap;
+        if (mIsLargeScreen) {
+            // [left, top, right, bottom]
+            mPaddings[0] = onLeft
+                    ? mExpandedViewLargeScreenInset - pointerTotalHeight
+                    : mExpandedViewLargeScreenInset;
+            mPaddings[1] = 0;
+            mPaddings[2] = onLeft
+                    ? mExpandedViewLargeScreenInset
+                    : mExpandedViewLargeScreenInset - pointerTotalHeight;
+            // Overflow doesn't show manage button / get padding from it so add padding here for it
+            mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
+            return mPaddings;
+        } else {
+            int leftPadding = mInsets.left + mExpandedViewPadding;
+            int rightPadding = mInsets.right + mExpandedViewPadding;
+            final float expandedViewWidth = isOverflow
+                    ? mOverflowWidth
+                    : mExpandedViewLargeScreenWidth;
+            if (showBubblesVertically()) {
+                if (!onLeft) {
+                    rightPadding += mBubbleSize - pointerTotalHeight;
+                    leftPadding += isOverflow
+                            ? (mPositionRect.width() - rightPadding - expandedViewWidth)
+                            : 0;
+                } else {
+                    leftPadding += mBubbleSize - pointerTotalHeight;
+                    rightPadding += isOverflow
+                            ? (mPositionRect.width() - leftPadding - expandedViewWidth)
+                            : 0;
+                }
             }
+            // [left, top, right, bottom]
+            mPaddings[0] = leftPadding;
+            mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
+            mPaddings[2] = rightPadding;
+            mPaddings[3] = 0;
+            return mPaddings;
         }
-        // [left, top, right, bottom]
-        mPaddings[0] = leftPadding;
-        mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
-        mPaddings[2] = rightPadding;
-        mPaddings[3] = 0;
-        return mPaddings;
     }
 
     /** Gets the y position of the expanded view if it was top-aligned. */
     private float getExpandedViewYTopAligned() {
         final int top = getAvailableRect().top;
         if (showBubblesVertically()) {
-            return top - mPointerWidth;
+            return top - mPointerWidth + mExpandedViewPadding;
         } else {
             return top + mBubbleSize + mPointerMargin;
         }
     }
 
-    /** The maximum height the expanded view can be. */
+    public float getExpandedBubblesY() {
+        return getAvailableRect().top + mExpandedViewPadding;
+    }
+
+    /**
+     * Calculate the maximum height the expanded view can be depending on where it's placed on
+     * the screen and the size of the elements around it (e.g. padding, pointer, manage button).
+     */
     public int getMaxExpandedViewHeight(boolean isOverflow) {
+        // Subtract top insets because availableRect.height would account for that
+        int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
         int paddingTop = showBubblesVertically()
                 ? 0
                 : mPointerHeight;
-        int settingsHeight = isOverflow ? 0 : mManageButtonHeight;
         // Subtract pointer size because it's laid out in LinearLayout with the expanded view.
         int pointerSize = showBubblesVertically()
                 ? mPointerWidth
                 : (mPointerHeight + mPointerMargin);
-        // Subtract top insets because availableRect.height would account for that
-        int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
+        int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
         return getAvailableRect().height()
                 - expandedContainerY
                 - paddingTop
-                - settingsHeight
-                - pointerSize;
+                - pointerSize
+                - bottomPadding;
     }
 
     /**
@@ -348,11 +398,14 @@
      */
     public float getExpandedViewHeight(BubbleViewProvider bubble) {
         boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
+        if (isOverflow && showBubblesVertically() && !mIsLargeScreen) {
+            // overflow in landscape on phone is max
+            return MAX_HEIGHT;
+        }
         float desiredHeight = isOverflow
                 ? mOverflowHeight
                 : ((Bubble) bubble).getDesiredHeight(mContext);
-        int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
-        desiredHeight = Math.max(manageButtonHeight + desiredHeight, mExpandedViewMinHeight);
+        desiredHeight = Math.max(desiredHeight, mExpandedViewMinHeight);
         if (desiredHeight > getMaxExpandedViewHeight(isOverflow)) {
             return MAX_HEIGHT;
         }
@@ -377,7 +430,7 @@
             return topAlignment;
         }
         // If we're here, we're showing vertically & developer has made height less than maximum.
-        int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
+        int manageButtonHeight = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
         float pointerPosition = getPointerPosition(bubblePosition);
         float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
         float topIfCentered = pointerPosition - (expandedViewHeight / 2);
@@ -412,25 +465,40 @@
     }
 
     /**
-     * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
-     * row. When in landscape or on a large screen, they show at the left or right side in a
-     * vertical row. This method accounts for screen orientation and will return an x or y value
-     * for the position of the bubble in the row.
+     * Returns the position of the bubble on-screen when the stack is expanded.
      *
-     * @param index bubble index in the row.
-     * @param numberOfBubbles the number of bubbles (including the overflow) in the row.
-     * @return the y position of the bubble if showing vertically and the x position if showing
-     * horizontally.
+     * @param index the index of the bubble in the stack.
+     * @param numberOfBubbles the total number of bubbles in the stack.
+     * @param onLeftEdge whether the stack would rest on the left edge of the screen when collapsed.
+     * @return the x, y position of the bubble on-screen when the stack is expanded.
      */
-    public float getBubbleXOrYForOrientation(int index, int numberOfBubbles) {
-        final float positionInBar = index * (mBubbleSize + mSpacingBetweenBubbles);
+    public PointF getExpandedBubbleXY(int index, int numberOfBubbles, boolean onLeftEdge) {
+        final float positionInRow = index * (mBubbleSize + mSpacingBetweenBubbles);
         final float expandedStackSize = (numberOfBubbles * mBubbleSize)
                 + ((numberOfBubbles - 1) * mSpacingBetweenBubbles);
         final float centerPosition = showBubblesVertically()
                 ? mPositionRect.centerY()
                 : mPositionRect.centerX();
+        // alignment - centered on the edge
         final float rowStart = centerPosition - (expandedStackSize / 2f);
-        return rowStart + positionInBar;
+        float x;
+        float y;
+        if (showBubblesVertically()) {
+            y = rowStart + positionInRow;
+            int left = mIsLargeScreen
+                    ? mExpandedViewLargeScreenInset - mExpandedViewPadding - mBubbleSize
+                    : mPositionRect.left;
+            int right = mIsLargeScreen
+                    ? mPositionRect.right - mExpandedViewLargeScreenInset + mExpandedViewPadding
+                    : mPositionRect.right - mBubbleSize;
+            x = onLeftEdge
+                    ? left
+                    : right;
+        } else {
+            y = mPositionRect.top + mExpandedViewPadding;
+            x = rowStart + positionInRow;
+        }
+        return new PointF(x, y);
     }
 
     /**
@@ -445,6 +513,17 @@
     }
 
     /**
+     * @return whether the stack is considered on the left side of the screen.
+     */
+    public boolean isStackOnLeft(PointF currentStackPosition) {
+        if (currentStackPosition == null) {
+            currentStackPosition = getRestingPosition();
+        }
+        final int stackCenter = (int) currentStackPosition.x + mBubbleSize / 2;
+        return stackCenter < mScreenRect.width() / 2;
+    }
+
+    /**
      * 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 8f2df4a..5bc6128 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
@@ -110,9 +110,6 @@
 
     private static final int FADE_IN_DURATION = 320;
 
-    /** Percent to darken the bubbles when they're in the dismiss target. */
-    private static final float DARKEN_PERCENT = 0.3f;
-
     /** How long to wait, in milliseconds, before hiding the flyout. */
     @VisibleForTesting
     static final int FLYOUT_HIDE_AFTER = 5000;
@@ -559,7 +556,7 @@
 
             if (mBubbleData.isExpanded()) {
                 if (mManageEduView != null) {
-                    mManageEduView.hide(false /* show */);
+                    mManageEduView.hide();
                 }
 
                 // If we're expanded, tell the animation controller to prepare to drag this bubble,
@@ -781,8 +778,8 @@
                 floatingContentCoordinator, this::getBubbleCount, onBubbleAnimatedOut,
                 this::animateShadows /* onStackAnimationFinished */, mPositioner);
 
-        mExpandedAnimationController = new ExpandedAnimationController(
-                mPositioner, mExpandedViewPadding, onBubbleAnimatedOut);
+        mExpandedAnimationController = new ExpandedAnimationController(mPositioner,
+                onBubbleAnimatedOut);
         mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
 
         // Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
@@ -797,8 +794,6 @@
         mBubbleContainer.setClipChildren(false);
         addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
 
-        updateUserEdu();
-
         mExpandedViewContainer = new FrameLayout(context);
         mExpandedViewContainer.setElevation(elevation);
         mExpandedViewContainer.setClipChildren(false);
@@ -932,8 +927,10 @@
         setOnClickListener(view -> {
             if (mShowingManage) {
                 showManageMenu(false /* show */);
+            } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+                mManageEduView.hide();
             } else if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
-                mStackEduView.hide(false);
+                mStackEduView.hide(false /* isExpanding */);
             } else if (mBubbleData.isExpanded()) {
                 mBubbleData.setExpanded(false);
             }
@@ -1132,10 +1129,10 @@
             return;
         }
         if (mManageEduView == null) {
-            mManageEduView = new ManageEducationView(mContext);
+            mManageEduView = new ManageEducationView(mContext, mPositioner);
             addView(mManageEduView);
         }
-        mManageEduView.show(mExpandedBubble.getExpandedView(), mTempRect);
+        mManageEduView.show(mExpandedBubble.getExpandedView());
     }
 
     /**
@@ -1163,21 +1160,27 @@
             return false;
         }
         if (mStackEduView == null) {
-            mStackEduView = new StackEducationView(mContext);
+            mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
             addView(mStackEduView);
         }
         mBubbleContainer.bringToFront();
         return mStackEduView.show(mPositioner.getDefaultStartPosition());
     }
 
+    // Recreates & shows the education views. Call when a theme/config change happens.
     private void updateUserEdu() {
-        maybeShowStackEdu();
-        if (mManageEduView != null) {
-            mManageEduView.invalidate();
+        if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
+            removeView(mStackEduView);
+            mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
+            addView(mStackEduView);
+            mBubbleContainer.bringToFront(); // Stack appears on top of the stack education
+            mStackEduView.show(mPositioner.getDefaultStartPosition());
         }
-        maybeShowManageEdu();
-        if (mStackEduView != null) {
-            mStackEduView.invalidate();
+        if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+            removeView(mManageEduView);
+            mManageEduView = new ManageEducationView(mContext, mPositioner);
+            addView(mManageEduView);
+            mManageEduView.show(mExpandedBubble.getExpandedView());
         }
     }
 
@@ -1274,6 +1277,7 @@
         setUpManageMenu();
         setUpFlyout();
         setUpDismissView();
+        updateUserEdu();
         mBubbleSize = mPositioner.getBubbleSize();
         for (Bubble b : mBubbleData.getBubbles()) {
             if (b.getIconView() == null) {
@@ -1311,6 +1315,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
+        mPositioner.update();
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
         getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
     }
@@ -1730,6 +1735,21 @@
         notifyExpansionChanged(mExpandedBubble, mIsExpanded);
     }
 
+    /**
+     * Called when back press occurs while bubbles are expanded.
+     */
+    public void onBackPressed() {
+        if (mIsExpanded) {
+            if (mShowingManage) {
+                showManageMenu(false);
+            } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+                mManageEduView.hide();
+            } else {
+                setExpanded(false);
+            }
+        }
+    }
+
     void setBubbleVisibility(Bubble b, boolean visible) {
         if (b.getIconView() != null) {
             b.getIconView().setVisibility(visible ? VISIBLE : GONE);
@@ -1850,28 +1870,28 @@
                 maybeShowManageEdu();
             }
         } /* after */);
-
-        final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
-                getBubbleIndex(mExpandedBubble));
-        mExpandedViewContainer.setTranslationX(0f);
-        mExpandedViewContainer.setTranslationY(translationY);
-        mExpandedViewContainer.setAlpha(1f);
-
         int index;
         if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
             index = mBubbleData.getBubbles().size();
         } else {
             index = getBubbleIndex(mExpandedBubble);
         }
-        // Position of the bubble we're expanding, once it's settled in its row.
-        final float bubbleWillBeAt =
-                mExpandedAnimationController.getBubbleXOrYForOrientation(index);
+        PointF p = mPositioner.getExpandedBubbleXY(index, mBubbleContainer.getChildCount(),
+                mStackOnLeftOrWillBe);
+        final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
+                mPositioner.showBubblesVertically() ? p.y : p.x);
+        mExpandedViewContainer.setTranslationX(0f);
+        mExpandedViewContainer.setTranslationY(translationY);
+        mExpandedViewContainer.setAlpha(1f);
 
         // How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
         // that are animating farther, so that the expanded view doesn't move as much.
         final float relevantStackPosition = showVertically
                 ? mStackAnimationController.getStackPosition().y
                 : mStackAnimationController.getStackPosition().x;
+        final float bubbleWillBeAt = showVertically
+                ? p.y
+                : p.x;
         final float distanceAnimated = Math.abs(bubbleWillBeAt - relevantStackPosition);
 
         // Wait for the path animation target to reach its end, and add a small amount of extra time
@@ -1888,22 +1908,22 @@
         // Set the pivot point for the scale, so the expanded view animates out from the bubble.
         if (showVertically) {
             float pivotX;
-            float pivotY = bubbleWillBeAt + mBubbleSize / 2f;
             if (mStackOnLeftOrWillBe) {
-                pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
+                pivotX = p.x + mBubbleSize + mExpandedViewPadding;
             } else {
-                pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;
+                pivotX = p.x - mExpandedViewPadding;
             }
             mExpandedViewContainerMatrix.setScale(
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
-                    pivotX, pivotY);
+                    pivotX,
+                    p.y + mBubbleSize / 2f);
         } else {
             mExpandedViewContainerMatrix.setScale(
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
-                    bubbleWillBeAt + mBubbleSize / 2f,
-                    translationY);
+                    p.x + mBubbleSize / 2f,
+                    p.y + mBubbleSize + mExpandedViewPadding);
         }
         mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
 
@@ -1940,6 +1960,7 @@
                                 mExpandedViewContainerMatrix);
                     })
                     .withEndActions(() -> {
+                        mExpandedViewContainer.setAnimationMatrix(null);
                         afterExpandedViewAnimation();
                         if (mExpandedBubble != null
                                 && mExpandedBubble.getExpandedView() != null) {
@@ -1955,6 +1976,9 @@
     private void animateCollapse() {
         cancelDelayedExpandCollapseSwitchAnimations();
 
+        if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+            mManageEduView.hide();
+        }
         // Hide the menu if it's visible.
         showManageMenu(false);
 
@@ -1987,12 +2011,11 @@
             index = mBubbleData.getBubbles().indexOf(mExpandedBubble);
         }
         // Value the bubble is animating from (back into the stack).
-        final float expandingFromBubbleAt =
-                mExpandedAnimationController.getBubbleXOrYForOrientation(index);
-        final boolean showVertically = mPositioner.showBubblesVertically();
+        final PointF p = mPositioner.getExpandedBubbleXY(index,
+                mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
         if (mPositioner.showBubblesVertically()) {
             float pivotX;
-            float pivotY = expandingFromBubbleAt + mBubbleSize / 2f;
+            float pivotY = p.y + mBubbleSize / 2f;
             if (mStackOnLeftOrWillBe) {
                 pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
             } else {
@@ -2004,8 +2027,8 @@
         } else {
             mExpandedViewContainerMatrix.setScale(
                     1f, 1f,
-                    expandingFromBubbleAt + mBubbleSize / 2f,
-                    mPositioner.getExpandedViewY(mExpandedBubble, index));
+                    p.x + mBubbleSize / 2f,
+                    p.y + mBubbleSize + mExpandedViewPadding);
         }
 
         mExpandedViewAlphaAnimator.reverse();
@@ -2032,7 +2055,7 @@
                     final BubbleViewProvider previouslySelected = mExpandedBubble;
                     beforeExpandedViewAnimation();
                     if (mManageEduView != null) {
-                        mManageEduView.hide(false /* fromExpansion */);
+                        mManageEduView.hide();
                     }
 
                     if (DEBUG_BUBBLE_STACK_VIEW) {
@@ -2083,32 +2106,31 @@
 
         boolean isOverflow = mExpandedBubble != null
                 && mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
-        float expandingFromBubbleDestination =
-                mExpandedAnimationController.getBubbleXOrYForOrientation(isOverflow
-                        ? getBubbleCount()
-                        : mBubbleData.getBubbles().indexOf(mExpandedBubble));
-
+        PointF p = mPositioner.getExpandedBubbleXY(isOverflow
+                        ? mBubbleContainer.getChildCount() - 1
+                        : mBubbleData.getBubbles().indexOf(mExpandedBubble),
+                    mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
         mExpandedViewContainer.setAlpha(1f);
         mExpandedViewContainer.setVisibility(View.VISIBLE);
 
         if (mPositioner.showBubblesVertically()) {
             float pivotX;
-            float pivotY = expandingFromBubbleDestination + mBubbleSize / 2f;
+            float pivotY = p.y + mBubbleSize / 2f;
             if (mStackOnLeftOrWillBe) {
-                pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
+                pivotX = p.x + mBubbleSize + mExpandedViewPadding;
             } else {
-                pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;
-
+                pivotX = p.x - mExpandedViewPadding;
             }
             mExpandedViewContainerMatrix.setScale(
-                    0f, 0f,
+                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
+                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     pivotX, pivotY);
         } else {
             mExpandedViewContainerMatrix.setScale(
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
-                    expandingFromBubbleDestination + mBubbleSize / 2f,
-                    mPositioner.getExpandedViewY(mExpandedBubble, expandingFromBubbleDestination));
+                    p.x + mBubbleSize / 2f,
+                    p.y + mBubbleSize + mExpandedViewPadding);
         }
 
         mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -2133,6 +2155,7 @@
                     .withEndActions(() -> {
                         mExpandedViewTemporarilyHidden = false;
                         mIsBubbleSwitchAnimating = false;
+                        mExpandedViewContainer.setAnimationMatrix(null);
                     })
                     .start();
         }, 25);
@@ -2742,16 +2765,17 @@
         }
         boolean isOverflowExpanded = mExpandedBubble != null
                 && BubbleOverflow.KEY.equals(mExpandedBubble.getKey());
-        int[] paddings = mPositioner.getExpandedViewPadding(
+        int[] paddings = mPositioner.getExpandedViewContainerPadding(
                 mStackAnimationController.isStackOnLeftSide(), isOverflowExpanded);
         mExpandedViewContainer.setPadding(paddings[0], paddings[1], paddings[2], paddings[3]);
         if (mIsExpansionAnimating) {
             mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
         }
         if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+            PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble),
+                    mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
             mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY(mExpandedBubble,
-                    mExpandedAnimationController.getBubbleXOrYForOrientation(
-                            getBubbleIndex(mExpandedBubble))));
+                    mPositioner.showBubblesVertically() ? p.y : p.x));
             mExpandedViewContainer.setTranslationX(0f);
             mExpandedBubble.getExpandedView().updateView(
                     mExpandedViewContainer.getLocationOnScreen());
@@ -2834,8 +2858,13 @@
         if (index == -1) {
             return;
         }
-        float bubblePosition = mExpandedAnimationController.getBubbleXOrYForOrientation(index);
-        mExpandedBubble.getExpandedView().setPointerPosition(bubblePosition, mStackOnLeftOrWillBe);
+        PointF bubblePosition = mPositioner.getExpandedBubbleXY(index,
+                mBubbleContainer.getChildCount(),
+                mStackOnLeftOrWillBe);
+        mExpandedBubble.getExpandedView().setPointerPosition(mPositioner.showBubblesVertically()
+                ? bubblePosition.y
+                : bubblePosition.x,
+                mStackOnLeftOrWillBe);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
index 4cc6702..eb4737a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
@@ -18,12 +18,13 @@
 import android.content.Context
 import android.graphics.Color
 import android.graphics.Rect
+import android.graphics.drawable.ColorDrawable
 import android.view.LayoutInflater
 import android.view.View
+import android.view.ViewGroup
 import android.widget.Button
 import android.widget.LinearLayout
-import android.widget.TextView
-import com.android.internal.util.ContrastColorUtil
+import com.android.internal.R.color.system_neutral1_900
 import com.android.wm.shell.R
 import com.android.wm.shell.animation.Interpolators
 
@@ -31,21 +32,22 @@
  * User education view to highlight the manage button that allows a user to configure the settings
  * for the bubble. Shown only the first time a user expands a bubble.
  */
-class ManageEducationView constructor(context: Context) : LinearLayout(context) {
+class ManageEducationView constructor(context: Context, positioner: BubblePositioner)
+    : LinearLayout(context) {
 
-    private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
+    private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "ManageEducationView"
         else BubbleDebugConfig.TAG_BUBBLES
 
     private val ANIMATE_DURATION: Long = 200
-    private val ANIMATE_DURATION_SHORT: Long = 40
 
-    private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
-    private val manageButton by lazy { findViewById<Button>(R.id.manage) }
+    private val positioner: BubblePositioner = positioner
+    private val manageView by lazy { findViewById<ViewGroup>(R.id.manage_education_view) }
+    private val manageButton by lazy { findViewById<Button>(R.id.manage_button) }
     private val gotItButton by lazy { findViewById<Button>(R.id.got_it) }
-    private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) }
-    private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) }
 
     private var isHiding = false
+    private var realManageButtonRect = Rect()
+    private var bubbleExpandedView: BubbleExpandedView? = null
 
     init {
         LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this)
@@ -66,18 +68,17 @@
     override fun onFinishInflate() {
         super.onFinishInflate()
         layoutDirection = resources.configuration.layoutDirection
-        setTextColor()
     }
 
-    private fun setTextColor() {
-        val typedArray = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
-            android.R.attr.textColorPrimaryInverse))
-        val bgColor = typedArray.getColor(0 /* index */, Color.BLACK)
-        var textColor = typedArray.getColor(1 /* index */, Color.WHITE)
+    private fun setButtonColor() {
+        val typedArray = mContext.obtainStyledAttributes(intArrayOf(
+                com.android.internal.R.attr.colorAccentPrimary))
+        val buttonColor = typedArray.getColor(0 /* index */, Color.TRANSPARENT)
         typedArray.recycle()
-        textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true)
-        titleTextView.setTextColor(textColor)
-        descTextView.setTextColor(textColor)
+
+        manageButton.setTextColor(mContext.getColor(system_neutral1_900))
+        manageButton.setBackgroundDrawable(ColorDrawable(buttonColor))
+        gotItButton.setBackgroundDrawable(ColorDrawable(buttonColor))
     }
 
     private fun setDrawableDirection() {
@@ -91,30 +92,39 @@
      * If necessary, toggles the user education view for the manage button. This is shown when the
      * bubble stack is expanded for the first time.
      *
-     * @param show whether the user education view should show or not.
+     * @param expandedView the expandedView the user education is shown on top of.
      */
-    fun show(expandedView: BubbleExpandedView, rect: Rect) {
+    fun show(expandedView: BubbleExpandedView) {
+        setButtonColor()
         if (visibility == VISIBLE) return
 
+        bubbleExpandedView = expandedView
+        expandedView.taskView?.setObscuredTouchRect(Rect(positioner.screenRect))
+
+        layoutParams.width = if (positioner.isLargeScreen)
+            context.resources.getDimensionPixelSize(
+                    R.dimen.bubbles_user_education_width_large_screen)
+        else ViewGroup.LayoutParams.MATCH_PARENT
+
         alpha = 0f
         visibility = View.VISIBLE
+        expandedView.getManageButtonBoundsOnScreen(realManageButtonRect)
+        manageView.setPadding(realManageButtonRect.left - expandedView.manageButtonMargin,
+                manageView.paddingTop, manageView.paddingRight, manageView.paddingBottom)
         post {
-            expandedView.getManageButtonBoundsOnScreen(rect)
-
             manageButton
                 .setOnClickListener {
-                    expandedView.findViewById<View>(R.id.settings_button).performClick()
-                    hide(true /* isStackExpanding */)
+                    hide()
+                    expandedView.findViewById<View>(R.id.manage_button).performClick()
                 }
-            gotItButton.setOnClickListener { hide(true /* isStackExpanding */) }
-            setOnClickListener { hide(true /* isStackExpanding */) }
+            gotItButton.setOnClickListener { hide() }
+            setOnClickListener { hide() }
 
-            with(manageView) {
-                translationX = 0f
-                val inset = resources.getDimensionPixelSize(
-                    R.dimen.bubbles_manage_education_top_inset)
-                translationY = (rect.top - manageView.height + inset).toFloat()
-            }
+            val offsetViewBounds = Rect()
+            manageButton.getDrawingRect(offsetViewBounds)
+            manageView.offsetDescendantRectToMyCoords(manageButton, offsetViewBounds)
+            translationX = 0f
+            translationY = (realManageButtonRect.top - offsetViewBounds.top).toFloat()
             bringToFront()
             animate()
                 .setDuration(ANIMATE_DURATION)
@@ -124,13 +134,14 @@
         setShouldShow(false)
     }
 
-    fun hide(isStackExpanding: Boolean) {
+    fun hide() {
+        bubbleExpandedView?.taskView?.setObscuredTouchRect(null)
         if (visibility != VISIBLE || isHiding) return
 
         animate()
             .withStartAction { isHiding = true }
             .alpha(0f)
-            .setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+            .setDuration(ANIMATE_DURATION)
             .withEndAction {
                 isHiding = false
                 visibility = GONE
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index 0a2cfc4..f6a90b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -18,8 +18,11 @@
 import android.content.Context
 import android.graphics.Color
 import android.graphics.PointF
+import android.view.KeyEvent
 import android.view.LayoutInflater
 import android.view.View
+import android.view.View.OnKeyListener
+import android.view.ViewGroup
 import android.widget.LinearLayout
 import android.widget.TextView
 import com.android.internal.util.ContrastColorUtil
@@ -30,7 +33,12 @@
  * User education view to highlight the collapsed stack of bubbles.
  * Shown only the first time a user taps the stack.
  */
-class StackEducationView constructor(context: Context) : LinearLayout(context) {
+class StackEducationView constructor(
+    context: Context,
+    positioner: BubblePositioner,
+    controller: BubbleController
+)
+    : LinearLayout(context) {
 
     private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
         else BubbleDebugConfig.TAG_BUBBLES
@@ -38,6 +46,9 @@
     private val ANIMATE_DURATION: Long = 200
     private val ANIMATE_DURATION_SHORT: Long = 40
 
+    private val positioner: BubblePositioner = positioner
+    private val controller: BubbleController = controller
+
     private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
     private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
     private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
@@ -67,6 +78,28 @@
         setTextColor()
     }
 
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        setFocusableInTouchMode(true)
+        setOnKeyListener(object : OnKeyListener {
+            override fun onKey(v: View?, keyCode: Int, event: KeyEvent): Boolean {
+                // if the event is a key down event on the enter button
+                if (event.action == KeyEvent.ACTION_UP &&
+                        keyCode == KeyEvent.KEYCODE_BACK && !isHiding) {
+                    hide(false)
+                    return true
+                }
+                return false
+            }
+        })
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        setOnKeyListener(null)
+        controller.updateWindowFlagsForBackpress(false /* interceptBack */)
+    }
+
     private fun setTextColor() {
         val ta = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
             android.R.attr.textColorPrimaryInverse))
@@ -94,13 +127,25 @@
     fun show(stackPosition: PointF): Boolean {
         if (visibility == VISIBLE) return false
 
+        controller.updateWindowFlagsForBackpress(true /* interceptBack */)
+        layoutParams.width = if (positioner.isLargeScreen)
+            context.resources.getDimensionPixelSize(
+                    R.dimen.bubbles_user_education_width_large_screen)
+        else ViewGroup.LayoutParams.MATCH_PARENT
+
         setAlpha(0f)
         setVisibility(View.VISIBLE)
         post {
+            requestFocus()
             with(view) {
-                val bubbleSize = context.resources.getDimensionPixelSize(
-                    R.dimen.bubble_size)
-                translationY = stackPosition.y + bubbleSize / 2 - getHeight() / 2
+                if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
+                    setPadding(positioner.bubbleSize + paddingRight, paddingTop, paddingRight,
+                            paddingBottom)
+                } else {
+                    setPadding(paddingLeft, paddingTop, positioner.bubbleSize + paddingLeft,
+                            paddingBottom)
+                }
+                translationY = stackPosition.y + positioner.bubbleSize / 2 - getHeight() / 2
             }
             animate()
                 .setDuration(ANIMATE_DURATION)
@@ -114,15 +159,16 @@
     /**
      * If necessary, hides the stack education view.
      *
-     * @param fromExpansion if true this indicates the hide is happening due to the bubble being
+     * @param isExpanding if true this indicates the hide is happening due to the bubble being
      *                      expanded, false if due to a touch outside of the bubble stack.
      */
-    fun hide(fromExpansion: Boolean) {
+    fun hide(isExpanding: Boolean) {
         if (visibility != VISIBLE || isHiding) return
 
+        controller.updateWindowFlagsForBackpress(false /* interceptBack */)
         animate()
             .alpha(0f)
-            .setDuration(if (fromExpansion) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+            .setDuration(if (isExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
             .withEndAction { visibility = GONE }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index efe07fb..c32be98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -64,9 +64,6 @@
     /** Stiffness for the expand/collapse path-following animation. */
     private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
 
-    /** What percentage of the screen to use when centering the bubbles in landscape. */
-    private static final float CENTER_BUBBLES_LANDSCAPE_PERCENT = 0.66f;
-
     /**
      * Velocity required to dismiss an individual bubble without dragging it into the dismiss
      * target.
@@ -79,8 +76,6 @@
 
     /** Horizontal offset between bubbles, which we need to know to re-stack them. */
     private float mStackOffsetPx;
-    /** Space between status bar and bubbles in the expanded state. */
-    private float mBubblePaddingTop;
     /** Size of each bubble. */
     private float mBubbleSizePx;
     /** Whether the expand / collapse animation is running. */
@@ -121,8 +116,6 @@
     /** The bubble currently being dragged out of the row (to potentially be dismissed). */
     private MagnetizedObject<View> mMagnetizedBubbleDraggingOut;
 
-    private int mExpandedViewPadding;
-
     /**
      * Callback to run whenever any bubble is animated out. The BubbleStackView will check if the
      * end of this animation means we have no bubbles left, and notify the BubbleController.
@@ -131,11 +124,10 @@
 
     private BubblePositioner mPositioner;
 
-    public ExpandedAnimationController(BubblePositioner positioner, int expandedViewPadding,
+    public ExpandedAnimationController(BubblePositioner positioner,
             Runnable onBubbleAnimatedOutAction) {
         mPositioner = positioner;
         updateResources();
-        mExpandedViewPadding = expandedViewPadding;
         mOnBubbleAnimatedOutAction = onBubbleAnimatedOutAction;
         mCollapsePoint = mPositioner.getDefaultStartPosition();
     }
@@ -202,7 +194,6 @@
             return;
         }
         Resources res = mLayout.getContext().getResources();
-        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
         mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
         mBubbleSizePx = mPositioner.getBubbleSize();
     }
@@ -248,31 +239,22 @@
             final Path path = new Path();
             path.moveTo(bubble.getTranslationX(), bubble.getTranslationY());
 
-            final float expandedY = mPositioner.showBubblesVertically()
-                    ? getBubbleXOrYForOrientation(index)
-                    : getExpandedY();
+            boolean onLeft = mPositioner.isStackOnLeft(mCollapsePoint);
+            final PointF p = mPositioner.getExpandedBubbleXY(index,
+                    mLayout.getChildCount(),
+                    onLeft);
             if (expanding) {
-                // If we're expanding, first draw a line from the bubble's current position to the
-                // top of the screen.
-                path.lineTo(bubble.getTranslationX(), expandedY);
+                // If we're expanding, first draw a line from the bubble's current position to where
+                // it'll end up
+                path.lineTo(bubble.getTranslationX(), p.y);
                 // Then, draw a line across the screen to the bubble's resting position.
-                if (mPositioner.showBubblesVertically()) {
-                    Rect availableRect = mPositioner.getAvailableRect();
-                    boolean onLeft = mCollapsePoint != null
-                            && mCollapsePoint.x < (availableRect.width() / 2f);
-                    float translationX = onLeft
-                            ? availableRect.left
-                            : availableRect.right - mBubbleSizePx;
-                    path.lineTo(translationX, getBubbleXOrYForOrientation(index));
-                } else {
-                    path.lineTo(getBubbleXOrYForOrientation(index), expandedY);
-                }
+                path.lineTo(p.x, p.y);
             } else {
                 final float stackedX = mCollapsePoint.x;
 
                 // If we're collapsing, draw a line from the bubble's current position to the side
                 // of the screen where the bubble will be stacked.
-                path.lineTo(stackedX, expandedY);
+                path.lineTo(stackedX, p.y);
 
                 // Then, draw a line down to the stack position.
                 path.lineTo(stackedX, mCollapsePoint.y
@@ -382,8 +364,9 @@
             bubbleView.setTranslationY(y);
         }
 
+        final float expandedY = mPositioner.getExpandedBubblesY();
         final boolean draggedOutEnough =
-                y > getExpandedY() + mBubbleSizePx || y < getExpandedY() - mBubbleSizePx;
+                y > expandedY + mBubbleSizePx || y < expandedY - mBubbleSizePx;
         if (draggedOutEnough != mBubbleDraggedOutEnough) {
             updateBubblePositions();
             mBubbleDraggedOutEnough = draggedOutEnough;
@@ -427,9 +410,10 @@
             return;
         }
         final int index = mLayout.indexOfChild(bubbleView);
-
+        final PointF p = mPositioner.getExpandedBubbleXY(index, mLayout.getChildCount(),
+                mPositioner.isStackOnLeft(mCollapsePoint));
         animationForChildAtIndex(index)
-                .position(getBubbleXOrYForOrientation(index), getExpandedY())
+                .position(p.x, p.y)
                 .withPositionStartVelocities(velX, velY)
                 .start(() -> bubbleView.setTranslationZ(0f) /* after */);
 
@@ -446,17 +430,13 @@
     }
 
     /**
-     * Animates the bubbles to {@link #getExpandedY()} position. Used in response to IME showing.
+     * Animates the bubbles to the y position. Used in response to IME showing.
      */
     public void updateYPosition(Runnable after) {
         if (mLayout == null) return;
         animationsForChildrenFromIndex(
-                0, (i, anim) -> anim.translationY(getExpandedY())).startAll(after);
-    }
-
-    /** The Y value of the row of expanded bubbles. */
-    public float getExpandedY() {
-        return mPositioner.getAvailableRect().top + mBubblePaddingTop;
+                0, (i, anim) -> anim.translationY(mPositioner.getExpandedBubblesY()))
+                .startAll(after);
     }
 
     /** Description of current animation controller state. */
@@ -514,35 +494,36 @@
             startOrUpdatePathAnimation(true /* expanding */);
         } else if (mAnimatingCollapse) {
             startOrUpdatePathAnimation(false /* expanding */);
-        } else if (mPositioner.showBubblesVertically()) {
-            child.setTranslationY(getBubbleXOrYForOrientation(index));
-            if (!mPreparingToCollapse) {
-                // Only animate if we're not collapsing as that animation will handle placing the
-                // new bubble in the stacked position.
-                Rect availableRect = mPositioner.getAvailableRect();
-                boolean onLeft = mCollapsePoint != null
-                        && mCollapsePoint.x < (availableRect.width() / 2f);
-                float fromX = onLeft
-                        ? -mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR
-                        : availableRect.right + mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR;
-                float toX = onLeft
-                        ? availableRect.left + mExpandedViewPadding
-                        : availableRect.right - mBubbleSizePx - mExpandedViewPadding;
-                animationForChild(child)
-                        .translationX(fromX, toX)
-                        .start();
-                updateBubblePositions();
-            }
         } else {
-            child.setTranslationX(getBubbleXOrYForOrientation(index));
+            boolean onLeft = mPositioner.isStackOnLeft(mCollapsePoint);
+            final PointF p = mPositioner.getExpandedBubbleXY(index,
+                    mLayout.getChildCount(),
+                    onLeft);
+            if (mPositioner.showBubblesVertically()) {
+                child.setTranslationY(p.y);
+            } else {
+                child.setTranslationX(p.x);
+            }
             if (!mPreparingToCollapse) {
                 // Only animate if we're not collapsing as that animation will handle placing the
                 // new bubble in the stacked position.
-                float toY = getExpandedY();
-                float fromY = getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR;
-                animationForChild(child)
-                        .translationY(fromY, toY)
-                        .start();
+                if (mPositioner.showBubblesVertically()) {
+                    Rect availableRect = mPositioner.getAvailableRect();
+                    float fromX = onLeft
+                            ? -mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR
+                            : availableRect.right + mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR;
+                    animationForChild(child)
+                            .translationX(fromX, p.y)
+                            .start();
+                } else {
+                    // Only animate if we're not collapsing as that animation will handle placing
+                    // the new bubble in the stacked position.
+                    float fromY = mPositioner.getExpandedBubblesY() - mBubbleSizePx
+                            * ANIMATE_TRANSLATION_FACTOR;
+                    animationForChild(child)
+                            .translationY(fromY, p.y)
+                            .start();
+                }
                 updateBubblePositions();
             }
         }
@@ -591,7 +572,7 @@
         if (mAnimatingExpand || mAnimatingCollapse) {
             return;
         }
-
+        boolean onLeft = mPositioner.isStackOnLeft(mCollapsePoint);
         for (int i = 0; i < mLayout.getChildCount(); i++) {
             final View bubble = mLayout.getChildAt(i);
 
@@ -601,39 +582,11 @@
                 return;
             }
 
-            if (mPositioner.showBubblesVertically()) {
-                Rect availableRect = mPositioner.getAvailableRect();
-                boolean onLeft = mCollapsePoint != null
-                        && mCollapsePoint.x < (availableRect.width() / 2f);
-                animationForChild(bubble)
-                        .translationX(onLeft
-                                ? availableRect.left
-                                : availableRect.right - mBubbleSizePx)
-                        .translationY(getBubbleXOrYForOrientation(i))
-                        .start();
-            } else {
-                animationForChild(bubble)
-                        .translationX(getBubbleXOrYForOrientation(i))
-                        .translationY(getExpandedY())
-                        .start();
-            }
+            final PointF p = mPositioner.getExpandedBubbleXY(i, mLayout.getChildCount(), onLeft);
+            animationForChild(bubble)
+                    .translationX(p.x)
+                    .translationY(p.y)
+                    .start();
         }
     }
-
-    /**
-     * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
-     * row. When in landscape or on a large screen, they show at the left or right side in a
-     * vertical row. This method accounts for screen orientation and will return an x or y value
-     * for the position of the bubble in the row.
-     *
-     * @param index bubble index in the row.
-     * @return the y position of the bubble if showing vertically and the x position if showing
-     * horizontally.
-     */
-    public float getBubbleXOrYForOrientation(int index) {
-        if (mLayout == null) {
-            return 0;
-        }
-        return mPositioner.getBubbleXOrYForOrientation(index, mLayout.getChildCount());
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 636e145..9a08190 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -305,10 +305,7 @@
         if (mLayout == null || !isStackPositionSet()) {
             return true; // Default to left, which is where it starts by default.
         }
-
-        float stackCenter = mStackPosition.x + mBubbleSize / 2;
-        float screenCenter = mLayout.getWidth() / 2;
-        return stackCenter < screenCenter;
+        return mPositioner.isStackOnLeft(mStackPosition);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index 3a7b534..ffda1f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.common;
 
 import android.os.RemoteException;
+import android.util.Slog;
 import android.view.IDisplayWindowRotationCallback;
 import android.view.IDisplayWindowRotationController;
 import android.view.IWindowManager;
@@ -27,6 +28,7 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 
 import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
@@ -35,14 +37,14 @@
  * rotation.
  */
 public class DisplayChangeController {
+    private static final String TAG = DisplayChangeController.class.getSimpleName();
 
     private final ShellExecutor mMainExecutor;
     private final IWindowManager mWmService;
     private final IDisplayWindowRotationController mControllerImpl;
 
-    private final ArrayList<OnDisplayChangingListener> mRotationListener =
-            new ArrayList<>();
-    private final ArrayList<OnDisplayChangingListener> mTmpListeners = new ArrayList<>();
+    private final CopyOnWriteArrayList<OnDisplayChangingListener> mRotationListener =
+            new CopyOnWriteArrayList<>();
 
     public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
@@ -59,34 +61,26 @@
      * Adds a display rotation controller.
      */
     public void addRotationListener(OnDisplayChangingListener listener) {
-        synchronized (mRotationListener) {
-            mRotationListener.add(listener);
-        }
+        mRotationListener.add(listener);
     }
 
     /**
      * Removes a display rotation controller.
      */
     public void removeRotationListener(OnDisplayChangingListener listener) {
-        synchronized (mRotationListener) {
-            mRotationListener.remove(listener);
-        }
+        mRotationListener.remove(listener);
     }
 
     private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
             IDisplayWindowRotationCallback callback) {
         WindowContainerTransaction t = new WindowContainerTransaction();
-        synchronized (mRotationListener) {
-            mTmpListeners.clear();
-            // Make a local copy in case the handlers add/remove themselves.
-            mTmpListeners.addAll(mRotationListener);
-        }
-        for (OnDisplayChangingListener c : mTmpListeners) {
+        for (OnDisplayChangingListener c : mRotationListener) {
             c.onRotateDisplay(displayId, fromRotation, toRotation, t);
         }
         try {
             callback.continueRotateDisplay(toRotation, t);
         } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to continue rotation", e);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index ba9ba5e..a1fb658 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -26,6 +26,7 @@
 import android.view.Display;
 import android.view.IDisplayWindowListener;
 import android.view.IWindowManager;
+import android.view.InsetsState;
 
 import androidx.annotation.BinderThread;
 
@@ -52,14 +53,6 @@
     private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
     private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
 
-    /**
-     * Gets a display by id from DisplayManager.
-     */
-    public Display getDisplay(int displayId) {
-        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
-        return displayManager.getDisplay(displayId);
-    }
-
     public DisplayController(Context context, IWindowManager wmService,
             ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
@@ -67,14 +60,31 @@
         mWmService = wmService;
         mChangeController = new DisplayChangeController(mWmService, mainExecutor);
         mDisplayContainerListener = new DisplayWindowListenerImpl();
+    }
+
+    /**
+     * Initializes the window listener.
+     */
+    public void initialize() {
         try {
-            mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+            int[] displayIds = mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+            for (int i = 0; i < displayIds.length; i++) {
+                onDisplayAdded(displayIds[i]);
+            }
         } catch (RemoteException e) {
-            throw new RuntimeException("Unable to register hierarchy listener");
+            throw new RuntimeException("Unable to register display controller");
         }
     }
 
     /**
+     * Gets a display by id from DisplayManager.
+     */
+    public Display getDisplay(int displayId) {
+        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        return displayManager.getDisplay(displayId);
+    }
+
+    /**
      * Gets the DisplayLayout associated with a display.
      */
     public @Nullable DisplayLayout getDisplayLayout(int displayId) {
@@ -91,6 +101,16 @@
     }
 
     /**
+     * Updates the insets for a given display.
+     */
+    public void updateDisplayInsets(int displayId, InsetsState state) {
+        final DisplayRecord r = mDisplays.get(displayId);
+        if (r != null) {
+            r.setInsets(state);
+        }
+    }
+
+    /**
      * Add a display window-container listener. It will get notified whenever a display's
      * configuration changes or when displays are added/removed from the WM hierarchy.
      */
@@ -134,17 +154,18 @@
             if (mDisplays.get(displayId) != null) {
                 return;
             }
-            Display display = getDisplay(displayId);
+            final Display display = getDisplay(displayId);
             if (display == null) {
                 // It's likely that the display is private to some app and thus not
                 // accessible by system-ui.
                 return;
             }
-            DisplayRecord record = new DisplayRecord();
-            record.mDisplayId = displayId;
-            record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+
+            final Context context = (displayId == Display.DEFAULT_DISPLAY)
+                    ? mContext
                     : mContext.createDisplayContext(display);
-            record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+            final DisplayRecord record = new DisplayRecord(displayId);
+            record.setDisplayLayout(context, new DisplayLayout(context, display));
             mDisplays.put(displayId, record);
             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                 mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -154,24 +175,23 @@
 
     private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
         synchronized (mDisplays) {
-            DisplayRecord dr = mDisplays.get(displayId);
+            final DisplayRecord dr = mDisplays.get(displayId);
             if (dr == null) {
                 Slog.w(TAG, "Skipping Display Configuration change on non-added"
                         + " display.");
                 return;
             }
-            Display display = getDisplay(displayId);
+            final Display display = getDisplay(displayId);
             if (display == null) {
                 Slog.w(TAG, "Skipping Display Configuration change on invalid"
                         + " display. It may have been removed.");
                 return;
             }
-            Context perDisplayContext = mContext;
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                perDisplayContext = mContext.createDisplayContext(display);
-            }
-            dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
-            dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+            final Context perDisplayContext = (displayId == Display.DEFAULT_DISPLAY)
+                    ? mContext
+                    : mContext.createDisplayContext(display);
+            final Context context = perDisplayContext.createConfigurationContext(newConfig);
+            dr.setDisplayLayout(context, new DisplayLayout(context, display));
             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                 mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
                         displayId, newConfig);
@@ -219,9 +239,25 @@
     }
 
     private static class DisplayRecord {
-        int mDisplayId;
-        Context mContext;
-        DisplayLayout mDisplayLayout;
+        private int mDisplayId;
+        private Context mContext;
+        private DisplayLayout mDisplayLayout;
+        private InsetsState mInsetsState = new InsetsState();
+
+        private DisplayRecord(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        private void setDisplayLayout(Context context, DisplayLayout displayLayout) {
+            mContext = context;
+            mDisplayLayout = displayLayout;
+            mDisplayLayout.setInsets(mContext.getResources(), mInsetsState);
+        }
+
+        private void setInsets(InsetsState state) {
+            mInsetsState = state;
+            mDisplayLayout.setInsets(mContext.getResources(), state);
+        }
     }
 
     @BinderThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index ba59e07..a7052bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -69,14 +69,17 @@
     protected final Executor mMainExecutor;
     private final TransactionPool mTransactionPool;
     private final DisplayController mDisplayController;
+    private final DisplayInsetsController mDisplayInsetsController;
     private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
     private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
 
 
     public DisplayImeController(IWindowManager wmService, DisplayController displayController,
+            DisplayInsetsController displayInsetsController,
             Executor mainExecutor, TransactionPool transactionPool) {
         mWmService = wmService;
         mDisplayController = displayController;
+        mDisplayInsetsController = displayInsetsController;
         mMainExecutor = mainExecutor;
         mTransactionPool = transactionPool;
     }
@@ -110,11 +113,11 @@
 
     @Override
     public void onDisplayRemoved(int displayId) {
-        try {
-            mWmService.setDisplayWindowInsetsController(displayId, null);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+        PerDisplay pd = mImePerDisplay.get(displayId);
+        if (pd == null) {
+            return;
         }
+        pd.unregister();
         mImePerDisplay.remove(displayId);
     }
 
@@ -196,12 +199,10 @@
     }
 
     /** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */
-    public class PerDisplay {
+    public class PerDisplay implements DisplayInsetsController.OnInsetsChangedListener {
         final int mDisplayId;
         final InsetsState mInsetsState = new InsetsState();
         final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
-        protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
-                new DisplayWindowInsetsControllerImpl();
         InsetsSourceControl mImeSourceControl = null;
         int mAnimationDirection = DIRECTION_NONE;
         ValueAnimator mAnimation = null;
@@ -216,14 +217,15 @@
         }
 
         public void register() {
-            try {
-                mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
-            }
+            mDisplayInsetsController.addInsetsChangedListener(mDisplayId, this);
         }
 
-        protected void insetsChanged(InsetsState insetsState) {
+        public void unregister() {
+            mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, this);
+        }
+
+        @Override
+        public void insetsChanged(InsetsState insetsState) {
             if (mInsetsState.equals(insetsState)) {
                 return;
             }
@@ -241,8 +243,9 @@
             }
         }
 
+        @Override
         @VisibleForTesting
-        protected void insetsControlChanged(InsetsState insetsState,
+        public void insetsControlChanged(InsetsState insetsState,
                 InsetsSourceControl[] activeControls) {
             insetsChanged(insetsState);
             InsetsSourceControl imeSourceControl = null;
@@ -303,7 +306,8 @@
             }
         }
 
-        protected void showInsets(int types, boolean fromIme) {
+        @Override
+        public void showInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
@@ -311,8 +315,8 @@
             startAnimation(true /* show */, false /* forceRestart */);
         }
 
-
-        protected void hideInsets(int types, boolean fromIme) {
+        @Override
+        public void hideInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
@@ -320,6 +324,7 @@
             startAnimation(false /* show */, false /* forceRestart */);
         }
 
+        @Override
         public void topFocusedWindowChanged(String packageName) {
             // Do nothing
         }
@@ -493,47 +498,6 @@
                 dispatchVisibilityChanged(mDisplayId, isShowing);
             }
         }
-
-        @VisibleForTesting
-        @BinderThread
-        public class DisplayWindowInsetsControllerImpl
-                extends IDisplayWindowInsetsController.Stub {
-            @Override
-            public void topFocusedWindowChanged(String packageName) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.topFocusedWindowChanged(packageName);
-                });
-            }
-
-            @Override
-            public void insetsChanged(InsetsState insetsState) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.insetsChanged(insetsState);
-                });
-            }
-
-            @Override
-            public void insetsControlChanged(InsetsState insetsState,
-                    InsetsSourceControl[] activeControls) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.insetsControlChanged(insetsState, activeControls);
-                });
-            }
-
-            @Override
-            public void showInsets(int types, boolean fromIme) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.showInsets(types, fromIme);
-                });
-            }
-
-            @Override
-            public void hideInsets(int types, boolean fromIme) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.hideInsets(types, fromIme);
-                });
-            }
-        }
     }
 
     void removeImeSurface() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
new file mode 100644
index 0000000..565f148
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -0,0 +1,265 @@
+/*
+ * 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.common;
+
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.IWindowManager;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.annotations.ShellMainThread;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Manages insets from the core.
+ */
+public class DisplayInsetsController implements DisplayController.OnDisplaysChangedListener {
+    private static final String TAG = "DisplayInsetsController";
+
+    private final IWindowManager mWmService;
+    private final ShellExecutor mMainExecutor;
+    private final DisplayController mDisplayController;
+    private final SparseArray<PerDisplay> mInsetsPerDisplay = new SparseArray<>();
+    private final SparseArray<CopyOnWriteArrayList<OnInsetsChangedListener>> mListeners =
+            new SparseArray<>();
+
+    public DisplayInsetsController(IWindowManager wmService, DisplayController displayController,
+            ShellExecutor mainExecutor) {
+        mWmService = wmService;
+        mDisplayController = displayController;
+        mMainExecutor = mainExecutor;
+    }
+
+    /**
+     * Starts listening for insets for each display.
+     **/
+    public void initialize() {
+        mDisplayController.addDisplayWindowListener(this);
+    }
+
+    /**
+     * Adds a callback to listen for insets changes for a particular display.  Note that the
+     * listener will not be updated with the existing state of the insets on that display.
+     */
+    public void addInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
+        CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
+        if (listeners == null) {
+            listeners = new CopyOnWriteArrayList<>();
+            mListeners.put(displayId, listeners);
+        }
+        if (!listeners.contains(listener)) {
+            listeners.add(listener);
+        }
+    }
+
+    /**
+     * Removes a callback listening for insets changes from a particular display.
+     */
+    public void removeInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
+        CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
+        if (listeners == null) {
+            return;
+        }
+        listeners.remove(listener);
+    }
+
+    @Override
+    public void onDisplayAdded(int displayId) {
+        PerDisplay pd = new PerDisplay(displayId);
+        pd.register();
+        mInsetsPerDisplay.put(displayId, pd);
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        PerDisplay pd = mInsetsPerDisplay.get(displayId);
+        if (pd == null) {
+            return;
+        }
+        pd.unregister();
+        mInsetsPerDisplay.remove(displayId);
+    }
+
+    /**
+     * An implementation of {@link IDisplayWindowInsetsController} for a given display id.
+     **/
+    public class PerDisplay {
+        private final int mDisplayId;
+        private final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
+                new DisplayWindowInsetsControllerImpl();
+
+        public PerDisplay(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        public void register() {
+            try {
+                mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
+            }
+        }
+
+        public void unregister() {
+            try {
+                mWmService.setDisplayWindowInsetsController(mDisplayId, null);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Unable to remove insets controller on display " + mDisplayId);
+            }
+        }
+
+        private void insetsChanged(InsetsState insetsState) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            mDisplayController.updateDisplayInsets(mDisplayId, insetsState);
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.insetsChanged(insetsState);
+            }
+        }
+
+        private void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.insetsControlChanged(insetsState, activeControls);
+            }
+        }
+
+        private void showInsets(int types, boolean fromIme) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.showInsets(types, fromIme);
+            }
+        }
+
+        private void hideInsets(int types, boolean fromIme) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.hideInsets(types, fromIme);
+            }
+        }
+
+        private void topFocusedWindowChanged(String packageName) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.topFocusedWindowChanged(packageName);
+            }
+        }
+
+        @BinderThread
+        private class DisplayWindowInsetsControllerImpl
+                extends IDisplayWindowInsetsController.Stub {
+            @Override
+            public void topFocusedWindowChanged(String packageName) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.topFocusedWindowChanged(packageName);
+                });
+            }
+
+            @Override
+            public void insetsChanged(InsetsState insetsState) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.insetsChanged(insetsState);
+                });
+            }
+
+            @Override
+            public void insetsControlChanged(InsetsState insetsState,
+                    InsetsSourceControl[] activeControls) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.insetsControlChanged(insetsState, activeControls);
+                });
+            }
+
+            @Override
+            public void showInsets(int types, boolean fromIme) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.showInsets(types, fromIme);
+                });
+            }
+
+            @Override
+            public void hideInsets(int types, boolean fromIme) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.hideInsets(types, fromIme);
+                });
+            }
+        }
+    }
+
+    /**
+     * Gets notified whenever the insets change.
+     *
+     * @see IDisplayWindowInsetsController
+     */
+    @ShellMainThread
+    public interface OnInsetsChangedListener {
+        /**
+         * Called when top focused window changes to determine whether or not to take over insets
+         * control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
+         * @param packageName: Passes the top package name
+         */
+        default void topFocusedWindowChanged(String packageName) {}
+
+        /**
+         * Called when the window insets configuration has changed.
+         */
+        default void insetsChanged(InsetsState insetsState) {}
+
+        /**
+         * Called when this window retrieved control over a specified set of insets sources.
+         */
+        default void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls) {}
+
+        /**
+         * Called when a set of insets source window should be shown by policy.
+         *
+         * @param types internal insets types (WindowInsets.Type.InsetsType) to show
+         * @param fromIme true if this request originated from IME (InputMethodService).
+         */
+        default void showInsets(int types, boolean fromIme) {}
+
+        /**
+         * Called when a set of insets source window should be hidden by policy.
+         *
+         * @param types internal insets types (WindowInsets.Type.InsetsType) to hide
+         * @param fromIme true if this request originated from IME (InputMethodService).
+         */
+        default void hideInsets(int types, boolean fromIme) {}
+    }
+}
\ No newline at end of file
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..962aca1 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
@@ -25,6 +25,7 @@
 import static android.util.RotationUtils.rotateBounds;
 import static android.util.RotationUtils.rotateInsets;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
@@ -44,7 +45,10 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
+import android.view.InsetsSource;
+import android.view.InsetsState;
 import android.view.Surface;
+import android.view.WindowInsets;
 
 import com.android.internal.R;
 
@@ -82,6 +86,10 @@
     private boolean mHasNavigationBar = false;
     private boolean mHasStatusBar = false;
     private int mNavBarFrameHeight = 0;
+    private boolean mAllowSeamlessRotationDespiteNavBarMoving = false;
+    private boolean mNavigationBarCanMove = false;
+    private boolean mReverseDefaultRotation = false;
+    private InsetsState mInsetsState = new InsetsState();
 
     @Override
     public boolean equals(Object o) {
@@ -98,14 +106,20 @@
                 && Objects.equals(mStableInsets, other.mStableInsets)
                 && mHasNavigationBar == other.mHasNavigationBar
                 && mHasStatusBar == other.mHasStatusBar
-                && mNavBarFrameHeight == other.mNavBarFrameHeight;
+                && mAllowSeamlessRotationDespiteNavBarMoving
+                        == other.mAllowSeamlessRotationDespiteNavBarMoving
+                && mNavigationBarCanMove == other.mNavigationBarCanMove
+                && mReverseDefaultRotation == other.mReverseDefaultRotation
+                && mNavBarFrameHeight == other.mNavBarFrameHeight
+                && Objects.equals(mInsetsState, other.mInsetsState);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
                 mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
-                mNavBarFrameHeight);
+                mNavBarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving,
+                mNavigationBarCanMove, mReverseDefaultRotation, mInsetsState);
     }
 
     /**
@@ -150,9 +164,13 @@
         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);
+        mInsetsState.set(dl.mInsetsState, true /* copySources */);
     }
 
     private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
@@ -165,12 +183,24 @@
         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);
+    }
+
+    /**
+     * Updates the current insets.
+     */
+    public void setInsets(Resources res, InsetsState state) {
+        mInsetsState = state;
         recalcInsets(res);
     }
 
     private void recalcInsets(Resources res) {
-        computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mUiMode, mNonDecorInsets,
-                mHasNavigationBar);
+        computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mInsetsState, mUiMode,
+                mNonDecorInsets, mHasNavigationBar);
         mStableInsets.set(mNonDecorInsets);
         if (mHasStatusBar) {
             convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
@@ -244,11 +274,33 @@
         return mWidth > mHeight;
     }
 
-    /** Get the navbar frame height (used by ime). */
+    /** Get the navbar frame (or window) height (used by ime). */
     public int navBarFrameHeight() {
         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;
@@ -291,21 +343,29 @@
      * @param outInsets the insets to return
      */
     static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
-            int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
-            boolean hasNavigationBar) {
+            int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode,
+            Rect outInsets, boolean hasNavigationBar) {
         outInsets.setEmpty();
 
         // Only navigation bar
         if (hasNavigationBar) {
+            final InsetsSource extraNavBar = insetsState.getSource(ITYPE_EXTRA_NAVIGATION_BAR);
+            final boolean hasExtraNav = extraNavBar != null && extraNavBar.isVisible();
             int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
             int navBarSize =
                     getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
             if (position == NAV_BAR_BOTTOM) {
-                outInsets.bottom = navBarSize;
+                outInsets.bottom = hasExtraNav
+                        ? Math.max(navBarSize, extraNavBar.getFrame().height())
+                        : navBarSize;
             } else if (position == NAV_BAR_RIGHT) {
-                outInsets.right = navBarSize;
+                outInsets.right = hasExtraNav
+                        ? Math.max(navBarSize, extraNavBar.getFrame().width())
+                        : navBarSize;
             } else if (position == NAV_BAR_LEFT) {
-                outInsets.left = navBarSize;
+                outInsets.left = hasExtraNav
+                        ? Math.max(navBarSize, extraNavBar.getFrame().width())
+                        : navBarSize;
             }
         }
 
@@ -327,13 +387,13 @@
      * @param outInsets the insets to return
      */
     static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
-            int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
-            boolean hasNavigationBar, boolean hasStatusBar) {
+            int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode,
+            Rect outInsets, boolean hasNavigationBar, boolean hasStatusBar) {
         outInsets.setEmpty();
 
         // Navigation bar and status bar.
         computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
-                uiMode, outInsets, hasNavigationBar);
+                insetsState, uiMode, outInsets, hasNavigationBar);
         convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
                 hasStatusBar);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
index f3a8620..4c0281d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
@@ -68,6 +68,10 @@
      * Queues a sync transaction to be sent serially to WM.
      */
     public void queue(WindowContainerTransaction wct) {
+        if (wct.isEmpty()) {
+            if (DEBUG) Slog.d(TAG, "Skip queue due to transaction change is empty");
+            return;
+        }
         SyncCallback cb = new SyncCallback(wct);
         synchronized (mQueue) {
             if (DEBUG) Slog.d(TAG, "Queueing up " + wct);
@@ -83,6 +87,10 @@
      */
     public void queue(LegacyTransitions.ILegacyTransition transition,
             @WindowManager.TransitionType int type, WindowContainerTransaction wct) {
+        if (wct.isEmpty()) {
+            if (DEBUG) Slog.d(TAG, "Skip queue due to transaction change is empty");
+            return;
+        }
         SyncCallback cb = new SyncCallback(transition, type, wct);
         synchronized (mQueue) {
             if (DEBUG) Slog.d(TAG, "Queueing up legacy transition " + wct);
@@ -99,6 +107,10 @@
      * @return {@code true} if queued, {@code false} if not.
      */
     public boolean queueIfWaiting(WindowContainerTransaction wct) {
+        if (wct.isEmpty()) {
+            if (DEBUG) Slog.d(TAG, "Skip queueIfWaiting due to transaction change is empty");
+            return false;
+        }
         synchronized (mQueue) {
             if (mQueue.isEmpty()) {
                 if (DEBUG) Slog.d(TAG, "Nothing in queue, so skip queueing up " + wct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
index 218bf47..c76937d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
@@ -70,7 +70,8 @@
     private final Paint mPaint = new Paint();
     private final int mWidth;
     private final int mHeight;
-    private final int mCircleDiameter;
+    private final int mTouchingWidth;
+    private final int mTouchingHeight;
     private int mCurrentWidth;
     private int mCurrentHeight;
     private AnimatorSet mAnimator;
@@ -80,11 +81,12 @@
         super(context, attrs);
         mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
         mPaint.setAntiAlias(true);
-        mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width);
-        mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height);
+        mWidth = getResources().getDimensionPixelSize(R.dimen.split_divider_handle_width);
+        mHeight = getResources().getDimensionPixelSize(R.dimen.split_divider_handle_height);
         mCurrentWidth = mWidth;
         mCurrentHeight = mHeight;
-        mCircleDiameter = (mWidth + mHeight) / 3;
+        mTouchingWidth = mWidth > mHeight ? mWidth / 2 : mWidth;
+        mTouchingHeight = mHeight > mWidth ? mHeight / 2 : mHeight;
     }
 
     /** Sets touching state for this handle view. */
@@ -98,16 +100,16 @@
         }
         if (!animate) {
             if (touching) {
-                mCurrentWidth = mCircleDiameter;
-                mCurrentHeight = mCircleDiameter;
+                mCurrentWidth = mTouchingWidth;
+                mCurrentHeight = mTouchingHeight;
             } else {
                 mCurrentWidth = mWidth;
                 mCurrentHeight = mHeight;
             }
             invalidate();
         } else {
-            animateToTarget(touching ? mCircleDiameter : mWidth,
-                    touching ? mCircleDiameter : mHeight, touching);
+            animateToTarget(touching ? mTouchingWidth : mWidth,
+                    touching ? mTouchingHeight : mHeight, touching);
         }
         mTouching = touching;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index cba019a..f35c8e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -19,15 +19,23 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
 
+import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Property;
+import android.util.TypedValue;
 import android.view.GestureDetector;
+import android.view.InsetsSource;
+import android.view.InsetsState;
 import android.view.MotionEvent;
 import android.view.SurfaceControlViewHost;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
@@ -44,6 +52,15 @@
     public static final long TOUCH_ANIMATION_DURATION = 150;
     public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
 
+    // TODO(b/191269755): use the value defined in InsetsController.
+    private static final Interpolator RESIZE_INTERPOLATOR = Interpolators.LINEAR;
+
+    // TODO(b/191269755): use the value defined in InsetsController.
+    private static final int ANIMATION_DURATION_RESIZE = 300;
+
+    /** The task bar expanded height. Used to determine whether to insets divider bounds or not. */
+    private float mExpandedTaskBarHeight;
+
     private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
 
     private SplitLayout mSplitLayout;
@@ -58,6 +75,31 @@
     private GestureDetector mDoubleTapDetector;
     private boolean mInteractive;
 
+    /**
+     * Tracks divider bar visible bounds in screen-based coordination. Used to calculate with
+     * insets.
+     */
+    private final Rect mDividerBounds = new Rect();
+    private final Rect mTempRect = new Rect();
+    private FrameLayout mDividerBar;
+
+
+    static final Property<DividerView, Integer> DIVIDER_HEIGHT_PROPERTY =
+            new Property<DividerView, Integer>(Integer.class, "height") {
+                @Override
+                public Integer get(DividerView object) {
+                    return object.mDividerBar.getLayoutParams().height;
+                }
+
+                @Override
+                public void set(DividerView object, Integer value) {
+                    ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
+                            object.mDividerBar.getLayoutParams();
+                    lp.height = value;
+                    object.mDividerBar.setLayoutParams(lp);
+                }
+            };
+
     public DividerView(@NonNull Context context) {
         super(context);
     }
@@ -79,16 +121,46 @@
     /** Sets up essential dependencies of the divider bar. */
     public void setup(
             SplitLayout layout,
-            SurfaceControlViewHost viewHost) {
+            SurfaceControlViewHost viewHost,
+            InsetsState insetsState) {
         mSplitLayout = layout;
         mViewHost = viewHost;
+        mDividerBounds.set(layout.getDividerBounds());
+        onInsetsChanged(insetsState, false /* animate */);
+    }
+
+    void onInsetsChanged(InsetsState insetsState, boolean animate) {
+        mTempRect.set(mSplitLayout.getDividerBounds());
+        final InsetsSource taskBarInsetsSource =
+                insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+        // Only insets the divider bar with task bar when it's expanded so that the rounded corners
+        // will be drawn against task bar.
+        if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
+            mTempRect.inset(taskBarInsetsSource.calculateVisibleInsets(mTempRect));
+        }
+
+        if (!mTempRect.equals(mDividerBounds)) {
+            if (animate) {
+                ObjectAnimator animator = ObjectAnimator.ofInt(this,
+                        DIVIDER_HEIGHT_PROPERTY, mDividerBounds.height(), mTempRect.height());
+                animator.setInterpolator(RESIZE_INTERPOLATOR);
+                animator.setDuration(ANIMATION_DURATION_RESIZE);
+                animator.start();
+            } else {
+                DIVIDER_HEIGHT_PROPERTY.set(this, mTempRect.height());
+            }
+            mDividerBounds.set(mTempRect);
+        }
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mDividerBar = findViewById(R.id.divider_bar);
         mHandle = findViewById(R.id.docked_divider_handle);
         mBackground = findViewById(R.id.docked_divider_background);
+        mExpandedTaskBarHeight = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.taskbar_frame_height);
         mTouchElevation = getResources().getDimensionPixelSize(
                 R.dimen.docked_stack_divider_lift_elevation);
         mDoubleTapDetector = new GestureDetector(getContext(), new DoubleTapListener());
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 b9ccd69..754b8da 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
@@ -18,11 +18,17 @@
 
 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 android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
 
 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;
@@ -32,7 +38,10 @@
 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.InsetsSourceControl;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -41,16 +50,19 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DockedDividerUtils;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 
 /**
  * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
  * divide position changes.
  */
-public final class SplitLayout {
+public final class SplitLayout implements DisplayInsetsController.OnInsetsChangedListener {
     /**
      * Split position isn't specified normally meaning to use what ever it is currently set to.
      */
@@ -80,18 +92,25 @@
     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();
     private final Rect mBounds2 = new Rect();
+    private final Rect mWinBounds1 = new Rect();
+    private final Rect mWinBounds2 = new Rect();
     private final SplitLayoutHandler mSplitLayoutHandler;
     private final SplitWindowManager mSplitWindowManager;
     private final DisplayImeController mDisplayImeController;
     private final ImePositionProcessor mImePositionProcessor;
+    private final DismissingParallaxPolicy mDismissingParallaxPolicy;
     private final ShellTaskOrganizer mTaskOrganizer;
+    private final InsetsState mInsetsState = new InsetsState();
 
     private Context mContext;
     private DividerSnapAlgorithm mDividerSnapAlgorithm;
+    private WindowContainerToken mWinToken1;
+    private WindowContainerToken mWinToken2;
     private int mDividePosition;
     private boolean mInitialized = false;
     private int mOrientation;
@@ -110,6 +129,7 @@
                 windowName, mContext, configuration, parentContainerCallbacks);
         mTaskOrganizer = taskOrganizer;
         mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
+        mDismissingParallaxPolicy = new DismissingParallaxPolicy();
 
         final Resources resources = context.getResources();
         mDividerWindowWidth = resources.getDimensionPixelSize(
@@ -148,6 +168,15 @@
         return mDividePosition;
     }
 
+    /**
+     * Returns the divider position as a fraction from 0 to 1.
+     */
+    public float getDividerPositionAsFraction() {
+        return Math.min(1f, Math.max(0f, isLandscape()
+                ? (float) ((mBounds1.right + mBounds2.left) / 2f) / mBounds2.right
+                : (float) ((mBounds1.bottom + mBounds2.top) / 2f) / mBounds2.bottom));
+    }
+
     /** Applies new configuration, returns {@code false} if there's no effect to the layout. */
     public boolean updateConfiguration(Configuration configuration) {
         boolean affectsLayout = false;
@@ -168,9 +197,10 @@
         final int rotation = configuration.windowConfiguration.getRotation();
         final Rect rootBounds = configuration.windowConfiguration.getBounds();
         if (rotation != mRotation || !mRootBounds.equals(rootBounds)) {
+            mTempRect.set(mRootBounds);
             mRootBounds.set(rootBounds);
             mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
-            resetDividerPosition();
+            initDividerPosition(mTempRect);
             affectsLayout = true;
         }
 
@@ -182,12 +212,26 @@
         return affectsLayout;
     }
 
+    private void initDividerPosition(Rect oldBounds) {
+        final float snapRatio = (float) mDividePosition
+                / (float) (isLandscape(oldBounds) ? oldBounds.width() : oldBounds.height());
+        // Estimate position by previous ratio.
+        final float length =
+                (float) (isLandscape() ? mRootBounds.width() : mRootBounds.height());
+        final int estimatePosition = (int) (length * snapRatio);
+        // Init divider position by estimated position using current bounds snap algorithm.
+        mDividePosition = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(
+                estimatePosition).position;
+        updateBounds(mDividePosition);
+    }
+
     /** Updates recording bounds of divider window and both of the splits. */
     private void updateBounds(int position) {
         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;
@@ -200,13 +244,16 @@
             mBounds1.bottom = position;
             mBounds2.top = mBounds1.bottom + mDividerSize;
         }
+        DockedDividerUtils.sanitizeStackBounds(mBounds1, true /** topLeft */);
+        DockedDividerUtils.sanitizeStackBounds(mBounds2, false /** topLeft */);
+        mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
     }
 
     /** Inflates {@link DividerView} on the root surface. */
     public void init() {
         if (mInitialized) return;
         mInitialized = true;
-        mSplitWindowManager.init(this);
+        mSplitWindowManager.init(this, mInsetsState);
         mDisplayImeController.addPositionProcessor(mImePositionProcessor);
     }
 
@@ -219,6 +266,23 @@
         mImePositionProcessor.reset();
     }
 
+    @Override
+    public void insetsChanged(InsetsState insetsState) {
+        mInsetsState.set(insetsState);
+        if (!mInitialized) {
+            return;
+        }
+        mSplitWindowManager.onInsetsChanged(insetsState);
+    }
+
+    @Override
+    public void insetsControlChanged(InsetsState insetsState,
+            InsetsSourceControl[] activeControls) {
+        if (!mInsetsState.equals(insetsState)) {
+            insetsChanged(insetsState);
+        }
+    }
+
     /**
      * Updates bounds with the passing position. Usually used to update recording bounds while
      * performing animation or dragging divider bar to resize the splits.
@@ -239,7 +303,12 @@
     /** Resets divider position. */
     public void resetDividerPosition() {
         mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+        mSplitWindowManager.setResizingSplits(false);
         updateBounds(mDividePosition);
+        mWinToken1 = null;
+        mWinToken2 = null;
+        mWinBounds1.setEmpty();
+        mWinBounds2.setEmpty();
     }
 
     /**
@@ -249,15 +318,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;
         }
     }
@@ -287,7 +356,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);
@@ -303,6 +373,9 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 setDividePosition(to);
+                if (flingFinishedCallback != null) {
+                    flingFinishedCallback.run();
+                }
             }
 
             @Override
@@ -325,33 +398,52 @@
         return bounds.width() > bounds.height();
     }
 
+    /**
+     * Return if this layout is landscape.
+     */
+    public boolean isLandscape() {
+        return isLandscape(mRootBounds);
+    }
+
     /** 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, SPLIT_DIVIDER_LAYER);
+        }
+        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;
+        }
+
+        if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
+            wct.setBounds(task1.token, mBounds1);
+            mWinBounds1.set(mBounds1);
+            mWinToken1 = task1.token;
+        }
+        if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) {
+            wct.setBounds(task2.token, mBounds2);
+            mWinBounds2.set(mBounds2);
+            mWinToken2 = task2.token;
+        }
     }
 
     /**
@@ -371,23 +463,22 @@
             wct.setScreenSizeDp(taskInfo2.token,
                     SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
         } else {
-            final Rect bounds = new Rect();
-            bounds.set(taskInfo1.configuration.windowConfiguration.getBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setBounds(taskInfo1.token, bounds);
-            bounds.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setAppBounds(taskInfo1.token, bounds);
+            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);
 
-            bounds.set(taskInfo2.configuration.windowConfiguration.getBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setBounds(taskInfo2.token, bounds);
-            bounds.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setAppBounds(taskInfo2.token, bounds);
+            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);
@@ -423,6 +514,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 {
         /**
@@ -553,24 +744,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/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index b7bbe80..fc7edfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -36,6 +36,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.IWindow;
+import android.view.InsetsState;
 import android.view.LayoutInflater;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
@@ -103,7 +104,7 @@
     }
 
     /** Inflates {@link DividerView} on to the root surface. */
-    void init(SplitLayout splitLayout) {
+    void init(SplitLayout splitLayout, InsetsState insetsState) {
         if (mDividerView != null || mViewHost != null) {
             throw new UnsupportedOperationException(
                     "Try to inflate divider view again without release first");
@@ -123,7 +124,7 @@
         lp.setTitle(mWindowName);
         lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
         mViewHost.setView(mDividerView, lp);
-        mDividerView.setup(splitLayout, mViewHost);
+        mDividerView.setup(splitLayout, mViewHost, insetsState);
     }
 
     /**
@@ -169,4 +170,10 @@
     SurfaceControl getSurfaceControl() {
         return mLeash;
     }
+
+    void onInsetsChanged(InsetsState insetsState) {
+        if (mDividerView != null) {
+            mDividerView.onInsetsChanged(insetsState, true /* animate */);
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 58bf22a..0c12d6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -34,6 +34,7 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -48,6 +49,8 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayController;
@@ -67,14 +70,17 @@
 
     private final Context mContext;
     private final DisplayController mDisplayController;
+    private final DragAndDropEventLogger mLogger;
     private SplitScreenController mSplitScreen;
 
     private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
     private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
 
-    public DragAndDropController(Context context, DisplayController displayController) {
+    public DragAndDropController(Context context, DisplayController displayController,
+            UiEventLogger uiEventLogger) {
         mContext = context;
         mDisplayController = displayController;
+        mLogger = new DragAndDropEventLogger(uiEventLogger);
     }
 
     public void initialize(Optional<SplitScreenController> splitscreen) {
@@ -175,9 +181,10 @@
                     Slog.w(TAG, "Unexpected drag start during an active drag");
                     return false;
                 }
+                InstanceId loggerSessionId = mLogger.logStart(event);
                 pd.activeDragCount++;
                 pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
-                        event.getClipData());
+                        event.getClipData(), loggerSessionId);
                 setDropTargetWindowVisibility(pd, View.VISIBLE);
                 break;
             case ACTION_DRAG_ENTERED:
@@ -198,7 +205,9 @@
             case ACTION_DRAG_ENDED:
                 // TODO(b/169894807): Ensure sure it's not possible to get ENDED without DROP
                 // or EXITED
-                if (!pd.dragLayout.hasDropped()) {
+                if (pd.dragLayout.hasDropped()) {
+                    mLogger.logDrop();
+                } else {
                     pd.activeDragCount--;
                     pd.dragLayout.hide(event, () -> {
                         if (pd.activeDragCount == 0) {
@@ -208,6 +217,7 @@
                         }
                     });
                 }
+                mLogger.logEnd();
                 break;
         }
         return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
new file mode 100644
index 0000000..6e4b815
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
@@ -0,0 +1,132 @@
+/*
+ * 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.draganddrop;
+
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.pm.ActivityInfo;
+import android.view.DragEvent;
+
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+/**
+ * Helper class that to log Drag & Drop UIEvents for a single session, see also go/uievent
+ */
+public class DragAndDropEventLogger {
+
+    private final UiEventLogger mUiEventLogger;
+    // Used to generate instance ids for this drag if one is not provided
+    private final InstanceIdSequence mIdSequence;
+
+    // Tracks the current drag session
+    private ActivityInfo mActivityInfo;
+    private InstanceId mInstanceId;
+
+    public DragAndDropEventLogger(UiEventLogger uiEventLogger) {
+        mUiEventLogger = uiEventLogger;
+        mIdSequence = new InstanceIdSequence(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Logs the start of a drag.
+     */
+    public InstanceId logStart(DragEvent event) {
+        final ClipDescription description = event.getClipDescription();
+        final ClipData data = event.getClipData();
+        final ClipData.Item item = data.getItemAt(0);
+        mInstanceId = item.getIntent().getParcelableExtra(
+                ClipDescription.EXTRA_LOGGING_INSTANCE_ID);
+        if (mInstanceId == null) {
+            mInstanceId = mIdSequence.newInstanceId();
+        }
+        mActivityInfo = item.getActivityInfo();
+        mUiEventLogger.logWithInstanceId(getStartEnum(description),
+                mActivityInfo.applicationInfo.uid,
+                mActivityInfo.applicationInfo.packageName, mInstanceId);
+        return mInstanceId;
+    }
+
+    /**
+     * Logs a successful drop.
+     */
+    public void logDrop() {
+        mUiEventLogger.logWithInstanceId(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_DROPPED,
+                mActivityInfo.applicationInfo.uid,
+                mActivityInfo.applicationInfo.packageName, mInstanceId);
+    }
+
+    /**
+     * Logs the end of a drag.
+     */
+    public void logEnd() {
+        mUiEventLogger.logWithInstanceId(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_END,
+                mActivityInfo.applicationInfo.uid,
+                mActivityInfo.applicationInfo.packageName, mInstanceId);
+    }
+
+    /**
+     * Returns the start logging enum for the given drag description.
+     */
+    private DragAndDropUiEventEnum getStartEnum(ClipDescription description) {
+        if (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)) {
+            return DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_ACTIVITY;
+        } else if (description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)) {
+            return DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_SHORTCUT;
+        } else if (description.hasMimeType(MIMETYPE_APPLICATION_TASK)) {
+            return DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_TASK;
+        }
+        throw new IllegalArgumentException("Not an app drag");
+    }
+
+    /**
+     * Enums for logging Drag & Drop UiEvents
+     */
+    public enum DragAndDropUiEventEnum implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Starting a global drag and drop of an activity")
+        GLOBAL_APP_DRAG_START_ACTIVITY(884),
+
+        @UiEvent(doc = "Starting a global drag and drop of a shortcut")
+        GLOBAL_APP_DRAG_START_SHORTCUT(885),
+
+        @UiEvent(doc = "Starting a global drag and drop of a task")
+        GLOBAL_APP_DRAG_START_TASK(888),
+
+        @UiEvent(doc = "A global app drag was successfully dropped")
+        GLOBAL_APP_DRAG_DROPPED(887),
+
+        @UiEvent(doc = "Ending a global app drag and drop")
+        GLOBAL_APP_DRAG_END(886);
+
+        private final int mId;
+
+        DragAndDropUiEventEnum(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+}
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 5b9d7b80..102b90f 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
@@ -63,6 +63,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.logging.InstanceId;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
 import com.android.wm.shell.splitscreen.SplitScreen.StageType;
@@ -86,6 +87,7 @@
     private final SplitScreenController mSplitScreen;
     private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
 
+    private InstanceId mLoggerSessionId;
     private DragSession mSession;
 
     public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
@@ -104,7 +106,8 @@
     /**
      * Starts a new drag session with the given initial drag data.
      */
-    void start(DisplayLayout displayLayout, ClipData data) {
+    void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
+        mLoggerSessionId = loggerSessionId;
         mSession = new DragSession(mContext, mActivityTaskManager, displayLayout, data);
         // TODO(b/169894807): Also update the session data with task stack changes
         mSession.update();
@@ -207,6 +210,8 @@
                 // Launch in the side stage if we are not in split-screen already.
                 stage = STAGE_TYPE_SIDE;
             }
+            // Add some data for logging splitscreen once it is invoked
+            mSplitScreen.logOnDroppedToSplit(position, mLoggerSessionId);
         }
 
         final ClipDescription description = data.getDescription();
@@ -294,7 +299,12 @@
                 @StageType int stage, @SplitPosition int position,
                 @Nullable Bundle options);
         void enterSplitScreen(int taskId, boolean leftOrTop);
-        void exitSplitScreen();
+
+        /**
+         * Exits splitscreen, with an associated exit trigger from the SplitscreenUIChanged proto
+         * for logging.
+         */
+        void exitSplitScreen(int exitTrigger);
     }
 
     /**
@@ -347,7 +357,7 @@
         }
 
         @Override
-        public void exitSplitScreen() {
+        public void exitSplitScreen(int exitTrigger) {
             throw new UnsupportedOperationException("exitSplitScreen not implemented by starter");
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index b342336..efc9ed0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -38,6 +38,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.logging.InstanceId;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
@@ -98,8 +99,9 @@
         return mHasDropped;
     }
 
-    public void prepare(DisplayLayout displayLayout, ClipData initialData) {
-        mPolicy.start(displayLayout, initialData);
+    public void prepare(DisplayLayout displayLayout, ClipData initialData,
+            InstanceId loggerSessionId) {
+        mPolicy.start(displayLayout, initialData, loggerSessionId);
         mHasDropped = false;
         mCurrentTarget = null;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
index 64f7be5..73deea5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
@@ -86,7 +86,7 @@
     public DropOutlineDrawable(Context context) {
         super();
         // TODO(b/169894807): Use corner specific radii and maybe lower radius for non-edge corners
-        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context.getResources());
+        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
         mColor = context.getColor(R.color.drop_outline_background);
         mMaxAlpha = Color.alpha(mColor);
         // Initialize as hidden
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/legacysplitscreen/LegacySplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
index 40244fb..f201634 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
@@ -62,6 +62,7 @@
     Rect mSecondary = null;
     Rect mAdjustedPrimary = null;
     Rect mAdjustedSecondary = null;
+    final Rect mTmpBounds = new Rect();
 
     public LegacySplitDisplayLayout(Context ctx, DisplayLayout dl,
             LegacySplitScreenTaskListener taskTiles) {
@@ -136,31 +137,41 @@
         return mMinimizedSnapAlgorithm;
     }
 
-    void resizeSplits(int position) {
+    /**
+     * Resize primary bounds and secondary bounds by divider position.
+     *
+     * @param position divider position.
+     * @return true if calculated bounds changed.
+     */
+    boolean resizeSplits(int position) {
         mPrimary = mPrimary == null ? new Rect() : mPrimary;
         mSecondary = mSecondary == null ? new Rect() : mSecondary;
-        calcSplitBounds(position, mPrimary, mSecondary);
+        int dockSide = getPrimarySplitSide();
+        boolean boundsChanged;
+
+        mTmpBounds.set(mPrimary);
+        DockedDividerUtils.calculateBoundsForPosition(position, dockSide, mPrimary,
+                mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
+        boundsChanged = !mPrimary.equals(mTmpBounds);
+
+        mTmpBounds.set(mSecondary);
+        DockedDividerUtils.calculateBoundsForPosition(position,
+                DockedDividerUtils.invertDockSide(dockSide), mSecondary, mDisplayLayout.width(),
+                mDisplayLayout.height(), mDividerSize);
+        boundsChanged |= !mSecondary.equals(mTmpBounds);
+        return boundsChanged;
     }
 
     void resizeSplits(int position, WindowContainerTransaction t) {
-        resizeSplits(position);
-        t.setBounds(mTiles.mPrimary.token, mPrimary);
-        t.setBounds(mTiles.mSecondary.token, mSecondary);
+        if (resizeSplits(position)) {
+            t.setBounds(mTiles.mPrimary.token, mPrimary);
+            t.setBounds(mTiles.mSecondary.token, mSecondary);
 
-        t.setSmallestScreenWidthDp(mTiles.mPrimary.token,
-                getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary));
-        t.setSmallestScreenWidthDp(mTiles.mSecondary.token,
-                getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary));
-    }
-
-    void calcSplitBounds(int position, @NonNull Rect outPrimary, @NonNull Rect outSecondary) {
-        int dockSide = getPrimarySplitSide();
-        DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outPrimary,
-                mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
-
-        DockedDividerUtils.calculateBoundsForPosition(position,
-                DockedDividerUtils.invertDockSide(dockSide), outSecondary, mDisplayLayout.width(),
-                mDisplayLayout.height(), mDividerSize);
+            t.setSmallestScreenWidthDp(mTiles.mPrimary.token,
+                    getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary));
+            t.setSmallestScreenWidthDp(mTiles.mSecondary.token,
+                    getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary));
+        }
     }
 
     Rect calcResizableMinimizedHomeStackBounds() {
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 d0491e95..9e1c61a 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
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.onehanded;
 
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
+
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Color;
@@ -46,7 +48,7 @@
  * the screen has entered one handed mode.
  */
 public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
-        implements OneHandedAnimationCallback {
+        implements OneHandedAnimationCallback, OneHandedState.OnStateChangedListener {
     private static final String TAG = "OneHandedBackgroundPanelOrganizer";
     private static final int THEME_COLOR_OFFSET = 10;
     private static final int ALPHA_ANIMATION_DURATION = 200;
@@ -56,6 +58,7 @@
     private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
             mTransactionFactory;
 
+    private @OneHandedState.State int mCurrentState;
     private ValueAnimator mAlphaAnimator;
 
     private float mTranslationFraction;
@@ -180,6 +183,9 @@
      * Called when transition finished.
      */
     public void onStopFinished() {
+        if (mAlphaAnimator == null) {
+            return;
+        }
         mAlphaAnimator.start();
     }
 
@@ -224,6 +230,10 @@
      */
     public void onConfigurationChanged() {
         updateThemeColors();
+
+        if (mCurrentState != STATE_ACTIVE) {
+            return;
+        }
         showBackgroundPanelLayer();
     }
 
@@ -242,6 +252,11 @@
         return Math.max(origColor - THEME_COLOR_OFFSET, 0) / 255.0f;
     }
 
+    @Override
+    public void onStateChanged(int newState) {
+        mCurrentState = newState;
+    }
+
     void dump(@NonNull PrintWriter pw) {
         final String innerPrefix = "  ";
         pw.println(TAG);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index b0fe856..954ca14 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -307,6 +307,7 @@
         mAccessibilityManager.addAccessibilityStateChangeListener(
                 mAccessibilityStateChangeListener);
 
+        mState.addSListeners(mBackgroundPanelOrganizer);
         mState.addSListeners(mTutorialHandler);
     }
 
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/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 1d238a1..9686776 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
@@ -613,7 +613,6 @@
 
     private void onEndOfSwipePipToHomeTransition() {
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mPipTransitionState.setInSwipePipToHomeTransition(false);
             mSwipePipToHomeOverlay = null;
             return;
         }
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..6fec1fb 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;
@@ -163,9 +170,12 @@
         if (request.getType() == TRANSIT_PIP) {
             WindowContainerTransaction wct = new WindowContainerTransaction();
             mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED);
-            final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
-            wct.setActivityWindowingMode(request.getTriggerTask().token, WINDOWING_MODE_UNDEFINED);
-            wct.setBounds(request.getTriggerTask().token, destinationBounds);
+            if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+                wct.setActivityWindowingMode(request.getTriggerTask().token,
+                        WINDOWING_MODE_UNDEFINED);
+                final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+                wct.setBounds(request.getTriggerTask().token, destinationBounds);
+            }
             return wct;
         } else {
             return null;
@@ -236,6 +246,7 @@
             onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, tx);
             sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
             mFinishCallback = null;
+            mPipTransitionState.setInSwipePipToHomeTransition(false);
             return true;
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index a646b07..ae8c1b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -60,8 +60,7 @@
     private static final boolean DEBUG = false;
 
     public static final int MENU_STATE_NONE = 0;
-    public static final int MENU_STATE_CLOSE = 1;
-    public static final int MENU_STATE_FULL = 2;
+    public static final int MENU_STATE_FULL = 1;
 
     /**
      * A listener interface to receive notification on changes in PIP.
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 92c0099..ac02075 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
@@ -27,6 +27,7 @@
 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_SAME;
 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;
@@ -84,6 +85,7 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipUtils;
+import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
 import java.util.Objects;
@@ -455,11 +457,18 @@
             return;
         }
         Runnable updateDisplayLayout = () -> {
+            final boolean fromRotation = Transitions.ENABLE_SHELL_TRANSITIONS
+                    && mPipBoundsState.getDisplayLayout().rotation() != layout.rotation();
             mPipBoundsState.setDisplayLayout(layout);
+            final WindowContainerTransaction wct =
+                    fromRotation ? new WindowContainerTransaction() : null;
             updateMovementBounds(null /* toBounds */,
-                    false /* fromRotation */, false /* fromImeAdjustment */,
+                    fromRotation, false /* fromImeAdjustment */,
                     false /* fromShelfAdjustment */,
-                    null /* windowContainerTransaction */);
+                    wct /* windowContainerTransaction */);
+            if (wct != null) {
+                mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME);
+            }
         };
 
         if (mPipTaskOrganizer.isInPip() && saveRestoreSnapFraction) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 67b1e6d..8ef2b6b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -23,7 +23,6 @@
 import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 
-import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
 import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
 import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
 
@@ -203,7 +202,7 @@
 
             @Override
             public boolean performAccessibilityAction(View host, int action, Bundle args) {
-                if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
+                if (action == ACTION_CLICK && mMenuState != MENU_STATE_FULL) {
                     mController.showMenu();
                 }
                 return super.performAccessibilityAction(host, action, args);
@@ -271,13 +270,12 @@
                     mDismissButton.getAlpha(), 1f);
             ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
                     mResizeHandle.getAlpha(),
-                    ENABLE_RESIZE_HANDLE && menuState == MENU_STATE_CLOSE && showResizeHandle
-                            ? 1f : 0f);
+                    ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
             if (menuState == MENU_STATE_FULL) {
                 mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
                         resizeAnim);
             } else {
-                mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
+                mMenuContainerAnimator.playTogether(resizeAnim);
             }
             mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
             mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -429,7 +427,7 @@
 
         FrameLayout.LayoutParams expandedLp =
                 (FrameLayout.LayoutParams) expandContainer.getLayoutParams();
-        if (mActions.isEmpty() || menuState == MENU_STATE_CLOSE || menuState == MENU_STATE_NONE) {
+        if (mActions.isEmpty() || menuState == MENU_STATE_NONE) {
             actionsContainer.setVisibility(View.INVISIBLE);
 
             // Update the expand container margin to adjust the center of the expand button to
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 7867f93..9f2f6a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -22,7 +22,6 @@
 import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
 import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
 import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
-import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
 import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
 import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
 import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_NONE;
@@ -81,7 +80,6 @@
 
     private final PhonePipMenuController mMenuController;
     private final AccessibilityManager mAccessibilityManager;
-    private boolean mShowPipMenuOnAnimationEnd = false;
 
     /**
      * Whether PIP stash is enabled or not. When enabled, if the user flings toward the edge of the
@@ -280,7 +278,6 @@
     public void onActivityPinned() {
         mPipDismissTargetHandler.createOrUpdateDismissTarget();
 
-        mShowPipMenuOnAnimationEnd = true;
         mPipResizeGestureHandler.onActivityPinned();
         mFloatingContentCoordinator.onContentAdded(mMotionHelper);
     }
@@ -304,13 +301,6 @@
             // Set the initial bounds as the user resize bounds.
             mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
         }
-
-        if (mShowPipMenuOnAnimationEnd) {
-            mMenuController.showMenu(MENU_STATE_CLOSE, mPipBoundsState.getBounds(),
-                    true /* allowMenuTimeout */, false /* willResizeMenu */,
-                    shouldShowResizeHandle());
-            mShowPipMenuOnAnimationEnd = false;
-        }
     }
 
     public void onConfigurationChanged() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
index 1fc4d12..ab3cbd6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
@@ -47,6 +47,8 @@
 
     /** Callback for size compat UI interaction. */
     public interface SizeCompatUICallback {
+        /** Called when the size compat restart button appears. */
+        void onSizeCompatRestartButtonAppeared(int taskId);
         /** Called when the size compat restart button is clicked. */
         void onSizeCompatRestartButtonClicked(int taskId);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index a5e96d1..7cf9559 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -28,6 +28,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -45,7 +46,7 @@
 class SizeCompatUILayout {
     private static final String TAG = "SizeCompatUILayout";
 
-    private final SyncTransactionQueue mSyncQueue;
+    final SyncTransactionQueue mSyncQueue;
     private final SizeCompatUIController.SizeCompatUICallback mCallback;
     private Context mContext;
     private Configuration mTaskConfig;
@@ -105,6 +106,8 @@
             mShouldShowHint = false;
             createSizeCompatHint();
         }
+
+        mCallback.onSizeCompatRestartButtonAppeared(mTaskId);
     }
 
     /** Creates the restart button hint window. */
@@ -306,6 +309,10 @@
 
     private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) {
         mSyncQueue.runInSync(t -> {
+            if (!leash.isValid()) {
+                Log.w(TAG, "The leash has been released.");
+                return;
+            }
             t.setPosition(leash, positionX, positionY);
             // The size compat UI should be the topmost child of the Task in case there can be more
             // than one children.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
index f634c45..82f69c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
@@ -110,7 +110,8 @@
         }
 
         if (mLeash != null) {
-            new SurfaceControl.Transaction().remove(mLeash).apply();
+            final SurfaceControl leash = mLeash;
+            mLayout.mSyncQueue.runInSync(t -> t.remove(leash));
             mLeash = null;
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index df1f5e6..2dd5393 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -22,7 +22,7 @@
 import android.os.UserHandle;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 
 import com.android.wm.shell.splitscreen.ISplitScreenListener;
 
@@ -82,7 +82,7 @@
      * Starts tasks simultaneously in one transition.
      */
     oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
-            in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10;
+            in Bundle sideOptions, int sidePosition, in RemoteTransition remoteTransition) = 10;
 
     /**
      * Version of startTasks using legacy transition system.
@@ -95,6 +95,8 @@
      * Blocking call that notifies and gets additional split-screen targets when entering
      * recents (for example: the dividerBar).
      * @param cancel is true if leaving recents back to split (eg. the gesture was cancelled).
+     * @param appTargets apps that will be re-parented to display area
      */
-    RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) = 12;
+    RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
+                                                   in RemoteAnimationTarget[] appTargets) = 12;
 }
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 7804c77..804fba7 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
@@ -22,7 +22,6 @@
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 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.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -42,17 +41,21 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
+import android.view.SurfaceSession;
 import android.view.WindowManager;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.logging.InstanceId;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -60,11 +63,11 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
-import com.android.wm.shell.splitscreen.ISplitScreenListener;
 import com.android.wm.shell.transition.LegacyTransitions;
 import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.concurrent.Executor;
 
 /**
@@ -72,6 +75,7 @@
  * {@link SplitScreen}.
  * @see StageCoordinator
  */
+// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
 public class SplitScreenController implements DragAndDropPolicy.Starter,
         RemoteCallable<SplitScreenController> {
     private static final String TAG = SplitScreenController.class.getSimpleName();
@@ -83,8 +87,10 @@
     private final ShellExecutor mMainExecutor;
     private final SplitScreenImpl mImpl = new SplitScreenImpl();
     private final DisplayImeController mDisplayImeController;
+    private final DisplayInsetsController mDisplayInsetsController;
     private final Transitions mTransitions;
     private final TransactionPool mTransactionPool;
+    private final SplitscreenEventLogger mLogger;
 
     private StageCoordinator mStageCoordinator;
 
@@ -92,6 +98,7 @@
             SyncTransactionQueue syncQueue, Context context,
             RootTaskDisplayAreaOrganizer rootTDAOrganizer,
             ShellExecutor mainExecutor, DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
             Transitions transitions, TransactionPool transactionPool) {
         mTaskOrganizer = shellTaskOrganizer;
         mSyncQueue = syncQueue;
@@ -99,8 +106,10 @@
         mRootTDAOrganizer = rootTDAOrganizer;
         mMainExecutor = mainExecutor;
         mDisplayImeController = displayImeController;
+        mDisplayInsetsController = displayInsetsController;
         mTransitions = transitions;
         mTransactionPool = transactionPool;
+        mLogger = new SplitscreenEventLogger();
     }
 
     public SplitScreen asSplitScreen() {
@@ -121,8 +130,8 @@
         if (mStageCoordinator == null) {
             // TODO: Multi-display
             mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
-                    mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mTransitions,
-                    mTransactionPool);
+                    mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
+                    mDisplayInsetsController, mTransitions, mTransactionPool, mLogger);
         }
     }
 
@@ -164,8 +173,8 @@
                 leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
     }
 
-    public void exitSplitScreen() {
-        mStageCoordinator.exitSplitScreen();
+    public void exitSplitScreen(int exitReason) {
+        mStageCoordinator.exitSplitScreen(exitReason);
     }
 
     public void onKeyguardOccludedChanged(boolean occluded) {
@@ -232,46 +241,34 @@
     private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
             @SplitScreen.StageType int stage, @SplitPosition int position,
             @Nullable Bundle options) {
-        final boolean wasInSplit = isSplitScreenVisible();
-
         LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
             @Override
             public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
                     RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                     IRemoteAnimationFinishedCallback finishedCallback,
                     SurfaceControl.Transaction t) {
-                boolean cancelled = apps == null || apps.length == 0;
                 mStageCoordinator.updateSurfaceBounds(null /* layout */, t);
-                if (cancelled) {
-                    if (!wasInSplit) {
-                        final WindowContainerTransaction undoWct = new WindowContainerTransaction();
-                        mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_MAIN, undoWct);
-                        mSyncQueue.queue(undoWct);
-                        mSyncQueue.runInSync(undoT -> {
-                            // looks weird, but we want undoT to execute after t but still want the
-                            // rest of the syncQueue runnables to aggregate.
-                            t.merge(undoT);
-                            undoT.merge(t);
-                        });
-                        return;
-                    }
-                } else {
+
+                if (apps != null) {
                     for (int i = 0; i < apps.length; ++i) {
                         if (apps[i].mode == MODE_OPENING) {
                             t.show(apps[i].leash);
                         }
                     }
                 }
-                RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
+
+                final RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
                 if (divider.leash != null) {
                     t.show(divider.leash);
                 }
+
                 t.apply();
-                if (cancelled) return;
-                try {
-                    finishedCallback.onAnimationFinished();
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Error finishing legacy transition: ", e);
+                if (finishedCallback != null) {
+                    try {
+                        finishedCallback.onAnimationFinished();
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error finishing legacy transition: ", e);
+                    }
                 }
             }
         };
@@ -281,11 +278,38 @@
         mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
     }
 
-    RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) {
+    RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, RemoteAnimationTarget[] apps) {
         if (!isSplitScreenVisible()) return null;
+        final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
+                .setContainerLayer()
+                .setName("RecentsAnimationSplitTasks")
+                .setHidden(false)
+                .setCallsite("SplitScreenController#onGoingtoRecentsLegacy");
+        mRootTDAOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, builder);
+        SurfaceControl sc = builder.build();
+        SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+
+        // Ensure that we order these in the parent in the right z-order as their previous order
+        Arrays.sort(apps, (a1, a2) -> a1.prefixOrderIndex - a2.prefixOrderIndex);
+        int layer = 1;
+        for (RemoteAnimationTarget appTarget : apps) {
+            transaction.reparent(appTarget.leash, sc);
+            transaction.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
+                    appTarget.screenSpaceBounds.top);
+            transaction.setLayer(appTarget.leash, layer++);
+        }
+        transaction.apply();
+        transaction.close();
         return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
     }
 
+    /**
+     * Sets drag info to be logged when splitscreen is entered.
+     */
+    public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
+        mStageCoordinator.logOnDroppedToSplit(position, dragSessionId);
+    }
+
     public void dump(@NonNull PrintWriter pw, String prefix) {
         pw.println(prefix + TAG);
         if (mStageCoordinator != null) {
@@ -478,7 +502,8 @@
         public void exitSplitScreen() {
             executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
                     (controller) -> {
-                        controller.exitSplitScreen();
+                        controller.exitSplitScreen(
+                                FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
                     });
         }
 
@@ -528,7 +553,7 @@
         public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
                 int sideTaskId, @Nullable Bundle sideOptions,
                 @SplitPosition int sidePosition,
-                @Nullable IRemoteTransition remoteTransition) {
+                @Nullable RemoteTransition remoteTransition) {
             executeRemoteCallWithTaskPermission(mController, "startTasks",
                     (controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
                             sideTaskId, sideOptions, sidePosition, remoteTransition));
@@ -554,10 +579,11 @@
         }
 
         @Override
-        public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) {
+        public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
+                RemoteAnimationTarget[] apps) {
             final RemoteAnimationTarget[][] out = new RemoteAnimationTarget[][]{null};
             executeRemoteCallWithTaskPermission(mController, "onGoingToRecentsLegacy",
-                    (controller) -> out[0] = controller.onGoingToRecentsLegacy(cancel),
+                    (controller) -> out[0] = controller.onGoingToRecentsLegacy(cancel, apps),
                     true /* blocking */);
             return out[0];
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 69d0be6..86e7b0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -35,7 +35,7 @@
 import android.os.IBinder;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
@@ -169,7 +169,7 @@
 
     /** Starts a transition to enter split with a remote transition animator. */
     IBinder startEnterTransition(@WindowManager.TransitionType int transitType,
-            @NonNull WindowContainerTransaction wct, @Nullable IRemoteTransition remoteTransition,
+            @NonNull WindowContainerTransaction wct, @Nullable RemoteTransition remoteTransition,
             @NonNull Transitions.TransitionHandler handler) {
         if (remoteTransition != null) {
             // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
new file mode 100644
index 0000000..319079b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -0,0 +1,324 @@
+/*
+ * 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.splitscreen;
+
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+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 com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
+
+/**
+ * Helper class that to log Drag & Drop UIEvents for a single session, see also go/uievent
+ */
+public class SplitscreenEventLogger {
+
+    // Used to generate instance ids for this drag if one is not provided
+    private final InstanceIdSequence mIdSequence;
+
+    // The instance id for the current splitscreen session (from start to end)
+    private InstanceId mLoggerSessionId;
+
+    // Drag info
+    private @SplitPosition int mDragEnterPosition;
+    private InstanceId mDragEnterSessionId;
+
+    // For deduping async events
+    private int mLastMainStagePosition = -1;
+    private int mLastMainStageUid = -1;
+    private int mLastSideStagePosition = -1;
+    private int mLastSideStageUid = -1;
+    private float mLastSplitRatio = -1f;
+
+    public SplitscreenEventLogger() {
+        mIdSequence = new InstanceIdSequence(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Return whether a splitscreen session has started.
+     */
+    public boolean hasStartedSession() {
+        return mLoggerSessionId != null;
+    }
+
+    /**
+     * May be called before logEnter() to indicate that the session was started from a drag.
+     */
+    public void enterRequestedByDrag(@SplitPosition int position, InstanceId dragSessionId) {
+        mDragEnterPosition = position;
+        mDragEnterSessionId = dragSessionId;
+    }
+
+    /**
+     * Logs when the user enters splitscreen.
+     */
+    public void logEnter(float splitRatio,
+            @SplitPosition int mainStagePosition, int mainStageUid,
+            @SplitPosition int sideStagePosition, int sideStageUid,
+            boolean isLandscape) {
+        mLoggerSessionId = mIdSequence.newInstanceId();
+        int enterReason = mDragEnterPosition != SPLIT_POSITION_UNDEFINED
+                ? getDragEnterReasonFromSplitPosition(mDragEnterPosition, isLandscape)
+                : SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+        updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
+                mainStageUid);
+        updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
+                sideStageUid);
+        updateSplitRatioState(splitRatio);
+        FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__ENTER,
+                enterReason,
+                0 /* exitReason */,
+                splitRatio,
+                mLastMainStagePosition,
+                mLastMainStageUid,
+                mLastSideStagePosition,
+                mLastSideStageUid,
+                mDragEnterSessionId != null ? mDragEnterSessionId.getId() : 0,
+                mLoggerSessionId.getId());
+    }
+
+    /**
+     * Logs when the user exits splitscreen.  Only one of the main or side stages should be
+     * specified to indicate which position was focused as a part of exiting (both can be unset).
+     */
+    public void logExit(int exitReason, @SplitPosition int mainStagePosition, int mainStageUid,
+            @SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
+        if (mLoggerSessionId == null) {
+            // Ignore changes until we've started logging the session
+            return;
+        }
+        if ((mainStagePosition != SPLIT_POSITION_UNDEFINED
+                && sideStagePosition != SPLIT_POSITION_UNDEFINED)
+                        || (mainStageUid != 0 && sideStageUid != 0)) {
+            throw new IllegalArgumentException("Only main or side stage should be set");
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__EXIT,
+                0 /* enterReason */,
+                exitReason,
+                0f /* splitRatio */,
+                getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
+                mainStageUid,
+                getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
+                sideStageUid,
+                0 /* dragInstanceId */,
+                mLoggerSessionId.getId());
+
+        // Reset states
+        mLoggerSessionId = null;
+        mDragEnterPosition = SPLIT_POSITION_UNDEFINED;
+        mDragEnterSessionId = null;
+        mLastMainStagePosition = -1;
+        mLastMainStageUid = -1;
+        mLastSideStagePosition = -1;
+        mLastSideStageUid = -1;
+    }
+
+    /**
+     * Logs when an app in the main stage changes.
+     */
+    public void logMainStageAppChange(@SplitPosition int mainStagePosition, int mainStageUid,
+            boolean isLandscape) {
+        if (mLoggerSessionId == null) {
+            // Ignore changes until we've started logging the session
+            return;
+        }
+        if (!updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition,
+                isLandscape), mainStageUid)) {
+            // Ignore if there are no user perceived changes
+            return;
+        }
+
+        FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__APP_CHANGE,
+                0 /* enterReason */,
+                0 /* exitReason */,
+                0f /* splitRatio */,
+                mLastMainStagePosition,
+                mLastMainStageUid,
+                0 /* sideStagePosition */,
+                0 /* sideStageUid */,
+                0 /* dragInstanceId */,
+                mLoggerSessionId.getId());
+    }
+
+    /**
+     * Logs when an app in the side stage changes.
+     */
+    public void logSideStageAppChange(@SplitPosition int sideStagePosition, int sideStageUid,
+            boolean isLandscape) {
+        if (mLoggerSessionId == null) {
+            // Ignore changes until we've started logging the session
+            return;
+        }
+        if (!updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition,
+                isLandscape), sideStageUid)) {
+            // Ignore if there are no user perceived changes
+            return;
+        }
+
+        FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__APP_CHANGE,
+                0 /* enterReason */,
+                0 /* exitReason */,
+                0f /* splitRatio */,
+                0 /* mainStagePosition */,
+                0 /* mainStageUid */,
+                mLastSideStagePosition,
+                mLastSideStageUid,
+                0 /* dragInstanceId */,
+                mLoggerSessionId.getId());
+    }
+
+    /**
+     * Logs when the splitscreen ratio changes.
+     */
+    public void logResize(float splitRatio) {
+        if (mLoggerSessionId == null) {
+            // Ignore changes until we've started logging the session
+            return;
+        }
+        if (splitRatio <= 0f || splitRatio >= 1f) {
+            // Don't bother reporting resizes that end up dismissing the split, that will be logged
+            // via the exit event
+            return;
+        }
+        if (!updateSplitRatioState(splitRatio)) {
+            // Ignore if there are no user perceived changes
+            return;
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__RESIZE,
+                0 /* enterReason */,
+                0 /* exitReason */,
+                mLastSplitRatio,
+                0 /* mainStagePosition */, 0 /* mainStageUid */,
+                0 /* sideStagePosition */, 0 /* sideStageUid */,
+                0 /* dragInstanceId */,
+                mLoggerSessionId.getId());
+    }
+
+    /**
+     * Logs when the apps in splitscreen are swapped.
+     */
+    public void logSwap(@SplitPosition int mainStagePosition, int mainStageUid,
+            @SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
+        if (mLoggerSessionId == null) {
+            // Ignore changes until we've started logging the session
+            return;
+        }
+
+        updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
+                mainStageUid);
+        updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
+                sideStageUid);
+        FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__SWAP,
+                0 /* enterReason */,
+                0 /* exitReason */,
+                0f /* splitRatio */,
+                mLastMainStagePosition,
+                mLastMainStageUid,
+                mLastSideStagePosition,
+                mLastSideStageUid,
+                0 /* dragInstanceId */,
+                mLoggerSessionId.getId());
+    }
+
+    private boolean updateMainStageState(int mainStagePosition, int mainStageUid) {
+        boolean changed = (mLastMainStagePosition != mainStagePosition)
+                || (mLastMainStageUid != mainStageUid);
+        if (!changed) {
+            return false;
+        }
+
+        mLastMainStagePosition = mainStagePosition;
+        mLastMainStageUid = mainStageUid;
+        return true;
+    }
+
+    private boolean updateSideStageState(int sideStagePosition, int sideStageUid) {
+        boolean changed = (mLastSideStagePosition != sideStagePosition)
+                || (mLastSideStageUid != sideStageUid);
+        if (!changed) {
+            return false;
+        }
+
+        mLastSideStagePosition = sideStagePosition;
+        mLastSideStageUid = sideStageUid;
+        return true;
+    }
+
+    private boolean updateSplitRatioState(float splitRatio) {
+        boolean changed = Float.compare(mLastSplitRatio, splitRatio) != 0;
+        if (!changed) {
+            return false;
+        }
+
+        mLastSplitRatio = splitRatio;
+        return true;
+    }
+
+    public int getDragEnterReasonFromSplitPosition(@SplitPosition int position,
+            boolean isLandscape) {
+        if (isLandscape) {
+            return position == SPLIT_POSITION_TOP_OR_LEFT
+                    ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_LEFT
+                    : FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_RIGHT;
+        } else {
+            return position == SPLIT_POSITION_TOP_OR_LEFT
+                    ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_TOP
+                    : FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__DRAG_BOTTOM;
+        }
+    }
+
+    private int getMainStagePositionFromSplitPosition(@SplitPosition int position,
+            boolean isLandscape) {
+        if (position == SPLIT_POSITION_UNDEFINED) {
+            return 0;
+        }
+        if (isLandscape) {
+            return position == SPLIT_POSITION_TOP_OR_LEFT
+                    ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__LEFT
+                    : FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__RIGHT;
+        } else {
+            return position == SPLIT_POSITION_TOP_OR_LEFT
+                    ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__TOP
+                    : FrameworkStatsLog.SPLITSCREEN_UICHANGED__MAIN_STAGE_POSITION__BOTTOM;
+        }
+    }
+
+    private int getSideStagePositionFromSplitPosition(@SplitPosition int position,
+            boolean isLandscape) {
+        if (position == SPLIT_POSITION_UNDEFINED) {
+            return 0;
+        }
+        if (isLandscape) {
+            return position == SPLIT_POSITION_TOP_OR_LEFT
+                    ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__LEFT
+                    : FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__RIGHT;
+        } else {
+            return position == SPLIT_POSITION_TOP_OR_LEFT
+                    ? FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__TOP
+                    : FrameworkStatsLog.SPLITSCREEN_UICHANGED__SIDE_STAGE_POSITION__BOTTOM;
+        }
+    }
+}
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 29e9917..33c3fb70 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
@@ -25,7 +25,14 @@
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.transitTypeToString;
+import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
 
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
 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;
@@ -65,7 +72,7 @@
 import android.view.SurfaceSession;
 import android.view.WindowManager;
 import android.window.DisplayAreaInfo;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerToken;
@@ -73,10 +80,12 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.InstanceId;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
@@ -128,7 +137,9 @@
     private final Context mContext;
     private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
     private final DisplayImeController mDisplayImeController;
+    private final DisplayInsetsController mDisplayInsetsController;
     private final SplitScreenTransitions mSplitTransitions;
+    private final SplitscreenEventLogger mLogger;
     private boolean mExitSplitScreenOnHide;
     private boolean mKeyguardOccluded;
 
@@ -154,13 +165,15 @@
 
     StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
             RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
-            DisplayImeController displayImeController, Transitions transitions,
-            TransactionPool transactionPool) {
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController, Transitions transitions,
+            TransactionPool transactionPool, SplitscreenEventLogger logger) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
         mRootTDAOrganizer = rootTDAOrganizer;
         mTaskOrganizer = taskOrganizer;
+        mLogger = logger;
         mMainStage = new MainStage(
                 mTaskOrganizer,
                 mDisplayId,
@@ -175,6 +188,7 @@
                 mSyncQueue,
                 mSurfaceSession);
         mDisplayImeController = displayImeController;
+        mDisplayInsetsController = displayInsetsController;
         mRootTDAOrganizer.registerListener(displayId, this);
         final DeviceStateManager deviceStateManager =
                 mContext.getSystemService(DeviceStateManager.class);
@@ -189,7 +203,9 @@
     StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
             RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
             MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController,
-            SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool) {
+            DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
+            Transitions transitions, TransactionPool transactionPool,
+            SplitscreenEventLogger logger) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
@@ -198,10 +214,12 @@
         mMainStage = mainStage;
         mSideStage = sideStage;
         mDisplayImeController = displayImeController;
+        mDisplayInsetsController = displayInsetsController;
         mRootTDAOrganizer.registerListener(displayId, this);
         mSplitLayout = splitLayout;
         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                 mOnTransitionAnimationComplete);
+        mLogger = logger;
         transitions.addHandler(this);
     }
 
@@ -245,7 +263,7 @@
     /** Starts 2 tasks in one transition. */
     void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
             @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
-            @Nullable IRemoteTransition remoteTransition) {
+            @Nullable RemoteTransition remoteTransition) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mainOptions = mainOptions != null ? mainOptions : new Bundle();
         sideOptions = sideOptions != null ? sideOptions : new Bundle();
@@ -340,7 +358,7 @@
     public void startIntent(PendingIntent intent, Intent fillInIntent,
             @SplitScreen.StageType int stage, @SplitPosition int position,
             @androidx.annotation.Nullable Bundle options,
-            @Nullable IRemoteTransition remoteTransition) {
+            @Nullable RemoteTransition remoteTransition) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         options = resolveStartStage(stage, position, options, wct);
         wct.sendPendingIntent(intent, fillInIntent, options);
@@ -375,7 +393,7 @@
                 if (options == null) {
                     options = new Bundle();
                 }
-                updateActivityOptions(options, position, wct);
+                updateActivityOptions(options, position);
                 break;
             }
             case STAGE_TYPE_MAIN: {
@@ -390,7 +408,7 @@
                 if (options == null) {
                     options = new Bundle();
                 }
-                updateActivityOptions(options, position, wct);
+                updateActivityOptions(options, position);
                 break;
             }
             default:
@@ -449,19 +467,20 @@
     void onKeyguardVisibilityChanged(boolean showing) {
         if (!showing && mMainStage.isActive()
                 && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
-            exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage);
+            exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
+                    SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED);
         }
     }
 
-    void exitSplitScreen() {
-        exitSplitScreen(null /* childrenToTop */);
+    void exitSplitScreen(int exitReason) {
+        exitSplitScreen(null /* childrenToTop */, exitReason);
     }
 
     void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mExitSplitScreenOnHide = exitSplitScreenOnHide;
     }
 
-    private void exitSplitScreen(StageTaskListener childrenToTop) {
+    private void exitSplitScreen(StageTaskListener childrenToTop, int exitReason) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mSideStage.removeAllTasks(wct, childrenToTop == mSideStage);
         mMainStage.deactivate(wct, childrenToTop == mMainStage);
@@ -469,6 +488,11 @@
         // Reset divider position.
         mSplitLayout.resetDividerPosition();
         mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+        if (childrenToTop != null) {
+            logExitToStage(exitReason, childrenToTop == mMainStage);
+        } else {
+            logExit(exitReason);
+        }
     }
 
     /**
@@ -491,22 +515,8 @@
         opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
     }
 
-    void updateActivityOptions(Bundle opts, @SplitPosition int position,
-            @Nullable WindowContainerTransaction wct) {
+    void updateActivityOptions(Bundle opts, @SplitPosition int position) {
         addActivityOptions(opts, position == mSideStagePosition ? mSideStage : mMainStage);
-
-        if (!mMainStage.isActive()) {
-            // Activate the main stage in anticipation of an app launch.
-            boolean needsApply = wct == null;
-            if (needsApply) {
-                wct = new WindowContainerTransaction();
-            }
-            mMainStage.activate(getMainStageBounds(), wct);
-            mSideStage.setBounds(getSideStageBounds(), wct);
-            if (needsApply) {
-                mTaskOrganizer.applyTransaction(wct);
-            }
-        }
     }
 
     void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
@@ -535,9 +545,8 @@
         }
     }
 
-    private void onStageChildTaskStatusChanged(
-            StageListenerImpl stageListener, int taskId, boolean present, boolean visible) {
-
+    private void onStageChildTaskStatusChanged(StageListenerImpl stageListener, int taskId,
+            boolean present, boolean visible) {
         int stage;
         if (present) {
             stage = stageListener == mSideStageListener ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
@@ -545,6 +554,13 @@
             // No longer on any stage
             stage = STAGE_TYPE_UNDEFINED;
         }
+        if (stage == STAGE_TYPE_MAIN) {
+            mLogger.logMainStageAppChange(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+                    mSplitLayout.isLandscape());
+        } else {
+            mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+                    mSplitLayout.isLandscape());
+        }
 
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onTaskStageChanged(taskId, stage, visible);
@@ -611,7 +627,7 @@
             // Don't dismiss staged split when both stages are not visible due to sleeping display,
             // like the cases keyguard showing or screen off.
             || (!mMainStage.mRootTaskInfo.isSleeping && !mSideStage.mRootTaskInfo.isSleeping)) {
-                exitSplitScreen();
+                exitSplitScreen(SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
             }
         } else if (mKeyguardOccluded) {
             // At least one of the stages is visible while keyguard occluded. Dismiss split because
@@ -619,7 +635,7 @@
             // task contains show-when-locked activity remains on top after split dismissed.
             final StageTaskListener toTop =
                     mainStageVisible ? mMainStage : (sideStageVisible ? mSideStage : null);
-            exitSplitScreen(toTop);
+            exitSplitScreen(toTop, SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP);
         }
 
         // When both stage's visibility changed to visible, main stage might receives visibility
@@ -686,7 +702,7 @@
 
         if (mDividerVisible) {
             t.show(dividerLeash)
-                    .setLayer(dividerLeash, Integer.MAX_VALUE)
+                    .setLayer(dividerLeash, SPLIT_DIVIDER_LAYER)
                     .setPosition(dividerLeash,
                             mSplitLayout.getDividerBounds().left,
                             mSplitLayout.getDividerBounds().top);
@@ -696,17 +712,16 @@
 
     }
 
-
     private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
         final boolean hasChildren = stageListener.mHasChildren;
         final boolean isSideStage = stageListener == mSideStageListener;
         if (!hasChildren) {
             if (isSideStage && mMainStageListener.mVisible) {
                 // Exit to main stage if side stage no longer has children.
-                exitSplitScreen(mMainStage);
+                exitSplitScreen(mMainStage, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED);
             } else if (!isSideStage && mSideStageListener.mVisible) {
                 // Exit to side stage if main stage no longer has children.
-                exitSplitScreen(mSideStage);
+                exitSplitScreen(mSideStage, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED);
             }
         } else if (isSideStage) {
             final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -715,6 +730,13 @@
             mSideStage.setBounds(getSideStageBounds(), wct);
             mTaskOrganizer.applyTransaction(wct);
         }
+        if (!mLogger.hasStartedSession() && mMainStageListener.mHasChildren
+                && mSideStageListener.mHasChildren) {
+            mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+                    getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+                    getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+                    mSplitLayout.isLandscape());
+        }
     }
 
     @VisibleForTesting
@@ -733,13 +755,17 @@
             onSnappedToDismissTransition(mainStageToTop);
             return;
         }
-        exitSplitScreen(mainStageToTop ? mMainStage : mSideStage);
+        exitSplitScreen(mainStageToTop ? mMainStage : mSideStage,
+                SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER);
     }
 
     @Override
     public void onDoubleTappedDivider() {
         setSideStagePosition(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
                 ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT, null /* wct */);
+        mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+                getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+                mSplitLayout.isLandscape());
     }
 
     @Override
@@ -753,6 +779,7 @@
         updateWindowBounds(layout, wct);
         mSyncQueue.queue(wct);
         mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
+        mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
     }
 
     /**
@@ -811,6 +838,7 @@
                     mDisplayAreaInfo.configuration, this,
                     b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
                     mDisplayImeController, mTaskOrganizer);
+            mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
         }
     }
 
@@ -1112,7 +1140,7 @@
         // Be default, make it visible. The remote animator can adjust alpha if it plans to animate.
         if (show) {
             t.setAlpha(leash, 1.f);
-            t.setLayer(leash, Integer.MAX_VALUE);
+            t.setLayer(leash, SPLIT_DIVIDER_LAYER);
             t.setPosition(leash, bounds.left, bounds.top);
             t.show(leash);
         }
@@ -1152,6 +1180,36 @@
         mMainStageListener.mHasChildren = mSideStageListener.mHasChildren = visible;
     }
 
+    /**
+     * Sets drag info to be logged when splitscreen is next entered.
+     */
+    public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
+        mLogger.enterRequestedByDrag(position, dragSessionId);
+    }
+
+    /**
+     * Logs the exit of splitscreen.
+     */
+    private void logExit(int exitReason) {
+        mLogger.logExit(exitReason,
+                SPLIT_POSITION_UNDEFINED, 0 /* mainStageUid */,
+                SPLIT_POSITION_UNDEFINED, 0 /* sideStageUid */,
+                mSplitLayout.isLandscape());
+    }
+
+    /**
+     * Logs the exit of splitscreen to a specific stage. This must be called before the exit is
+     * executed.
+     */
+    private void logExitToStage(int exitReason, boolean toMainStage) {
+        mLogger.logExit(exitReason,
+                toMainStage ? getMainStagePosition() : SPLIT_POSITION_UNDEFINED,
+                toMainStage ? mMainStage.getTopChildTaskUid() : 0 /* mainStageUid */,
+                !toMainStage ? getSideStagePosition() : SPLIT_POSITION_UNDEFINED,
+                !toMainStage ? mSideStage.getTopChildTaskUid() : 0 /* sideStageUid */,
+                mSplitLayout.isLandscape());
+    }
+
     class StageListenerImpl implements StageTaskListener.StageListenerCallbacks {
         boolean mHasRootTask = false;
         boolean mVisible = false;
@@ -1191,7 +1249,8 @@
         @Override
         public void onNoLongerSupportMultiWindow() {
             if (mMainStage.isActive()) {
-                StageCoordinator.this.exitSplitScreen();
+                StageCoordinator.this.exitSplitScreen(
+                        SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW);
             }
         }
 
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 c47353a..da91c1c 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,12 +97,36 @@
         return mChildrenTaskInfo.contains(taskId);
     }
 
+    /**
+     * Returns the top activity uid for the top child task.
+     */
+    int getTopChildTaskUid() {
+        for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+            final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
+            if (info.topActivityInfo == null) {
+                continue;
+            }
+            return info.topActivityInfo.applicationInfo.uid;
+        }
+        return 0;
+    }
+
     /** @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;
+        if (mRootTaskInfo == null) {
+            return false;
         }
+
+        if (mRootTaskInfo.isFocused) {
+            return true;
+        }
+
+        for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+            if (mChildrenTaskInfo.valueAt(i).isFocused) {
+                return true;
+            }
+        }
+
         return false;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 29326ec..8df7cbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -50,6 +50,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.view.ContextThemeWrapper;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.window.SplashScreenView;
@@ -137,12 +138,14 @@
      *                                 null if failed.
      */
     void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
-            int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) {
+            int taskId, Consumer<SplashScreenView> splashScreenViewConsumer,
+            Consumer<Runnable> uiThreadInitConsumer) {
         mSplashscreenWorkerHandler.post(() -> {
             SplashScreenView contentView;
             try {
                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView");
-                contentView = makeSplashScreenContentView(context, info, suggestType);
+                contentView = makeSplashScreenContentView(context, info, suggestType,
+                        uiThreadInitConsumer);
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "failed creating starting window content at taskId: "
@@ -238,7 +241,7 @@
     }
 
     private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
-            @StartingWindowType int suggestType) {
+            @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) {
         updateDensity();
 
         getWindowAttrs(context, mTmpAttrs);
@@ -253,6 +256,7 @@
                 .setWindowBGColor(themeBGColor)
                 .overlayDrawable(legacyDrawable)
                 .chooseStyle(suggestType)
+                .setUiThreadInitConsumer(uiThreadInitConsumer)
                 .build();
     }
 
@@ -299,6 +303,11 @@
         }
     }
 
+    /** Creates the wrapper with system theme to avoid unexpected styles from app. */
+    ContextThemeWrapper createViewContextWrapper(Context appContext) {
+        return new ContextThemeWrapper(appContext, mContext.getTheme());
+    }
+
     /** The configuration of the splash screen window. */
     public static class SplashScreenWindowAttrs {
         private int mWindowBgResId = 0;
@@ -318,6 +327,7 @@
         private int mThemeColor;
         private Drawable[] mFinalIconDrawables;
         private int mFinalIconSize = mIconSize;
+        private Consumer<Runnable> mUiThreadInitTask;
 
         StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
             mContext = context;
@@ -339,6 +349,11 @@
             return this;
         }
 
+        StartingWindowViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
+            mUiThreadInitTask = uiThreadInitTask;
+            return this;
+        }
+
         SplashScreenView build() {
             Drawable iconDrawable;
             final int animationDuration;
@@ -360,7 +375,7 @@
                 createIconDrawable(iconDrawable, false);
             } else {
                 final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
-                final int densityDpi = mContext.getResources().getDisplayMetrics().densityDpi;
+                final int densityDpi = mContext.getResources().getConfiguration().densityDpi;
                 final int scaledIconDpi =
                         (int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE);
                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon");
@@ -385,7 +400,8 @@
                 animationDuration = 0;
             }
 
-            return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration);
+            return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration,
+                    mUiThreadInitTask);
         }
 
         private class ShapeIconFactory extends BaseIconFactory {
@@ -463,7 +479,7 @@
         }
 
         private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable,
-                int animationDuration) {
+                int animationDuration, Consumer<Runnable> uiThreadInitTask) {
             Drawable foreground = null;
             Drawable background = null;
             if (iconDrawable != null) {
@@ -472,13 +488,15 @@
             }
 
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
-            final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext)
+            final ContextThemeWrapper wrapper = createViewContextWrapper(mContext);
+            final SplashScreenView.Builder builder = new SplashScreenView.Builder(wrapper)
                     .setBackgroundColor(mThemeColor)
                     .setOverlayDrawable(mOverlayDrawable)
                     .setIconSize(iconSize)
                     .setIconBackground(background)
                     .setCenterViewDrawable(foreground)
-                    .setAnimationDurationMillis(animationDuration);
+                    .setAnimationDurationMillis(animationDuration)
+                    .setUiThreadInitConsumer(uiThreadInitTask);
 
             if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
                     && mTmpAttrs.mBrandingImage != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 951b97e..f0685a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -304,6 +304,13 @@
             return true;
         }
 
+        @Override
+        public void stopAnimation() {
+            if (mIconAnimator != null) {
+                mIconAnimator.end();
+            }
+        }
+
         private final Callback mCallback = new Callback() {
             @Override
             public void invalidateDrawable(@NonNull Drawable who) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index 01c9b66..76105a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -36,4 +36,12 @@
     default int getBackgroundColor(TaskInfo taskInfo) {
         return Color.BLACK;
     }
+
+    /** Set the proxy to communicate with SysUi side components. */
+    void setSysuiProxy(SysuiProxy proxy);
+
+    /** Callback to tell SysUi components execute some methods. */
+    interface SysuiProxy {
+        void requestTopUi(boolean requestTopUi, String componentTag);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index fc7c86d..debe6d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -52,6 +52,7 @@
 import android.view.SurfaceControlViewHost;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.widget.FrameLayout;
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -115,6 +116,8 @@
     @VisibleForTesting
     final SplashscreenContentDrawer mSplashscreenContentDrawer;
     private Choreographer mChoreographer;
+    private final WindowManagerGlobal mWindowManagerGlobal;
+    private StartingSurface.SysuiProxy mSysuiProxy;
 
     /**
      * @param splashScreenExecutor The thread used to control add and remove starting window.
@@ -126,6 +129,8 @@
         mSplashScreenExecutor = splashScreenExecutor;
         mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, pool);
         mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
+        mWindowManagerGlobal = WindowManagerGlobal.getInstance();
+        mDisplayManager.getDisplay(DEFAULT_DISPLAY);
     }
 
     private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
@@ -137,29 +142,21 @@
     private final SparseArray<SurfaceControlViewHost> mAnimatedSplashScreenSurfaceHosts =
             new SparseArray<>(1);
 
-    /** Obtain proper context for showing splash screen on the provided display. */
-    private Context getDisplayContext(Context context, int displayId) {
-        if (displayId == DEFAULT_DISPLAY) {
-            // The default context fits.
-            return context;
-        }
-
-        final Display targetDisplay = mDisplayManager.getDisplay(displayId);
-        if (targetDisplay == null) {
-            // Failed to obtain the non-default display where splash screen should be shown,
-            // lets not show at all.
-            return null;
-        }
-
-        return context.createDisplayContext(targetDisplay);
+    private Display getDisplay(int displayId) {
+        return mDisplayManager.getDisplay(displayId);
     }
 
-    private int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) {
+    int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) {
         return splashScreenThemeResId != 0
                 ? splashScreenThemeResId
                 : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource()
                         : com.android.internal.R.style.Theme_DeviceDefault_DayNight;
     }
+
+    void setSysuiProxy(StartingSurface.SysuiProxy sysuiProxy) {
+        mSysuiProxy = sysuiProxy;
+    }
+
     /**
      * Called when a task need a splash screen starting window.
      *
@@ -177,7 +174,7 @@
 
         final int displayId = taskInfo.displayId;
         final int taskId = taskInfo.taskId;
-        Context context = mContext;
+
         // replace with the default theme if the application didn't set
         final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo);
         if (DEBUG_SPLASH_SCREEN) {
@@ -185,14 +182,16 @@
                     + " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId
                     + " suggestType=" + suggestType);
         }
-
-        // Obtain proper context to launch on the right display.
-        final Context displayContext = getDisplayContext(context, displayId);
-        if (displayContext == null) {
+        final Display display = getDisplay(displayId);
+        if (display == null) {
             // Can't show splash screen on requested display, so skip showing at all.
             return;
         }
-        context = displayContext;
+        Context context = displayId == DEFAULT_DISPLAY
+                ? mContext : mContext.createDisplayContext(display);
+        if (context == null) {
+            return;
+        }
         if (theme != context.getThemeResId()) {
             try {
                 context = context.createPackageContextAsUser(activityInfo.packageName,
@@ -303,7 +302,8 @@
         // Record whether create splash screen view success, notify to current thread after
         // create splash screen view finished.
         final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
-        final FrameLayout rootLayout = new FrameLayout(context);
+        final FrameLayout rootLayout = new FrameLayout(
+                mSplashscreenContentDrawer.createViewContextWrapper(context));
         rootLayout.setPadding(0, 0, 0, 0);
         rootLayout.setFitsSystemWindows(false);
         final Runnable setViewSynchronized = () -> {
@@ -328,12 +328,13 @@
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         };
+        if (mSysuiProxy != null) {
+            mSysuiProxy.requestTopUi(true, TAG);
+        }
         mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId,
-                viewSupplier::setView);
-
+                viewSupplier::setView, viewSupplier::setUiThreadInitTask);
         try {
-            final WindowManager wm = context.getSystemService(WindowManager.class);
-            if (addWindow(taskId, appToken, rootLayout, wm, params, suggestType)) {
+            if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) {
                 // We use the splash screen worker thread to create SplashScreenView while adding
                 // the window, as otherwise Choreographer#doFrame might be delayed on this thread.
                 // And since Choreographer#doFrame won't happen immediately after adding the window,
@@ -366,6 +367,7 @@
     private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> {
         private SplashScreenView mView;
         private boolean mIsViewSet;
+        private Runnable mUiThreadInitTask;
         void setView(SplashScreenView view) {
             synchronized (this) {
                 mView = view;
@@ -374,6 +376,12 @@
             }
         }
 
+        void setUiThreadInitTask(Runnable initTask) {
+            synchronized (this) {
+                mUiThreadInitTask = initTask;
+            }
+        }
+
         @Override
         public @Nullable SplashScreenView get() {
             synchronized (this) {
@@ -383,6 +391,10 @@
                     } catch (InterruptedException ignored) {
                     }
                 }
+                if (mUiThreadInitTask != null) {
+                    mUiThreadInitTask.run();
+                    mUiThreadInitTask = null;
+                }
                 return mView;
             }
         }
@@ -505,15 +517,17 @@
             Slog.v(TAG, reason + "the splash screen. Releasing SurfaceControlViewHost for task:"
                     + taskId);
         }
-        viewHost.getView().post(viewHost::release);
+        SplashScreenView.releaseIconHost(viewHost);
     }
 
-    protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm,
+    protected boolean addWindow(int taskId, IBinder appToken, View view, Display display,
             WindowManager.LayoutParams params, @StartingWindowType int suggestType) {
         boolean shouldSaveView = true;
+        final Context context = view.getContext();
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView");
-            wm.addView(view, params);
+            mWindowManagerGlobal.addView(view, params, display,
+                    null /* parentWindow */, context.getUserId());
         } catch (WindowManager.BadTokenException e) {
             // ignore
             Slog.w(TAG, appToken + " already running, starting window not displayed. "
@@ -521,9 +535,9 @@
             shouldSaveView = false;
         } finally {
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-            if (view != null && view.getParent() == null) {
+            if (view.getParent() == null) {
                 Slog.w(TAG, "view not successfully added to wm, removing view");
-                wm.removeViewImmediate(view);
+                mWindowManagerGlobal.removeView(view, true /* immediate */);
                 shouldSaveView = false;
             }
         }
@@ -584,13 +598,13 @@
     }
 
     private void removeWindowInner(View decorView, boolean hideView) {
+        if (mSysuiProxy != null) {
+            mSysuiProxy.requestTopUi(false, TAG);
+        }
         if (hideView) {
             decorView.setVisibility(View.GONE);
         }
-        final WindowManager wm = decorView.getContext().getSystemService(WindowManager.class);
-        if (wm != null) {
-            wm.removeView(decorView);
-        }
+        mWindowManagerGlobal.removeView(decorView, false /* immediate */);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index e84d498..a5c47c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -217,6 +217,11 @@
             return color != Color.TRANSPARENT
                     ? color : SplashscreenContentDrawer.getSystemBGColor();
         }
+
+        @Override
+        public void setSysuiProxy(SysuiProxy proxy) {
+            mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.setSysuiProxy(proxy));
+        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 7d011e6..cdc0795 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -343,7 +343,7 @@
 
     static Rect getSystemBarInsets(Rect frame, InsetsState state) {
         return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
-                false /* ignoreVisibility */);
+                false /* ignoreVisibility */).toRect();
     }
 
     private void drawSnapshot() {
@@ -364,6 +364,7 @@
 
         // In case window manager leaks us, make sure we don't retain the snapshot.
         mSnapshot = null;
+        mSurfaceControl.release();
     }
 
     private void drawSizeMatchSnapshot() {
@@ -431,6 +432,7 @@
             mTransaction.setBuffer(mSurfaceControl, background);
         }
         mTransaction.apply();
+        childSurfaceControl.release();
     }
 
     /**
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 01134a7..4ba6aca 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,16 +23,21 @@
 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;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 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;
@@ -68,9 +73,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;
@@ -97,6 +105,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;
@@ -114,8 +123,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;
@@ -126,6 +137,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,
@@ -133,10 +248,9 @@
             @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) {
+        // If keyguard goes away, we should loadKeyguardExitAnimation. Otherwise this just
+        // immediately finishes since there is no animation for screen-wake.
+        if (info.getType() == WindowManager.TRANSIT_WAKE && !info.isKeyguardGoingAway()) {
             startTransaction.apply();
             finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
             return true;
@@ -168,11 +282,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) {
@@ -234,7 +352,7 @@
         final int overrideType = options != null ? options.getType() : ANIM_NONE;
         final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true;
 
-        if (type == TRANSIT_KEYGUARD_GOING_AWAY) {
+        if (info.isKeyguardGoingAway()) {
             a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
                     (changeFlags & FLAG_SHOW_WALLPAPER) != 0);
         } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
index dffc700..bdcdb63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
@@ -16,7 +16,7 @@
 
 package com.android.wm.shell.transition;
 
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 
 /**
@@ -28,10 +28,10 @@
      * Registers a remote transition handler.
      */
     oneway void registerRemote(in TransitionFilter filter,
-            in IRemoteTransition remoteTransition) = 1;
+            in RemoteTransition remoteTransition) = 1;
 
     /**
      * Unregisters a remote transition handler.
      */
-    oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2;
+    oneway void unregisterRemote(in RemoteTransition remoteTransition) = 2;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 6bd8053..3be896e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -24,6 +24,7 @@
 import android.view.SurfaceControl;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
@@ -43,10 +44,10 @@
     private IBinder mTransition = null;
 
     /** The remote to delegate animation to */
-    private final IRemoteTransition mRemote;
+    private final RemoteTransition mRemote;
 
     public OneShotRemoteHandler(@NonNull ShellExecutor mainExecutor,
-            @NonNull IRemoteTransition remote) {
+            @NonNull RemoteTransition remote) {
         mMainExecutor = mainExecutor;
         mRemote = remote;
     }
@@ -88,7 +89,7 @@
             if (mRemote.asBinder() != null) {
                 mRemote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
             }
-            mRemote.startAnimation(transition, info, startTransaction, cb);
+            mRemote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error running remote transition.", e);
             if (mRemote.asBinder() != null) {
@@ -115,7 +116,7 @@
             }
         };
         try {
-            mRemote.mergeAnimation(transition, info, t, mergeTarget, cb);
+            mRemote.getRemoteTransition().mergeAnimation(transition, info, t, mergeTarget, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error merging remote transition.", e);
         }
@@ -125,8 +126,9 @@
     @Nullable
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
             @Nullable TransitionRequestInfo request) {
-        IRemoteTransition remote = request.getRemoteTransition();
-        if (remote != mRemote) return null;
+        RemoteTransition remote = request.getRemoteTransition();
+        IRemoteTransition iRemote = remote != null ? remote.getRemoteTransition() : null;
+        if (iRemote != mRemote.getRemoteTransition()) return null;
         mTransition = transition;
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "RemoteTransition directly requested"
                 + " for %s: %s", transition, remote);
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 bda884c..ac612a7 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
@@ -27,6 +27,7 @@
 import android.view.SurfaceControl;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
@@ -50,10 +51,10 @@
     private final ShellExecutor mMainExecutor;
 
     /** Includes remotes explicitly requested by, eg, ActivityOptions */
-    private final ArrayMap<IBinder, IRemoteTransition> mRequestedRemotes = new ArrayMap<>();
+    private final ArrayMap<IBinder, RemoteTransition> mRequestedRemotes = new ArrayMap<>();
 
     /** Ordered by specificity. Last filters will be checked first */
-    private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
+    private final ArrayList<Pair<TransitionFilter, RemoteTransition>> mFilters =
             new ArrayList<>();
 
     private final ArrayMap<IBinder, RemoteDeathHandler> mDeathHandlers = new ArrayMap<>();
@@ -62,19 +63,12 @@
         mMainExecutor = mainExecutor;
     }
 
-    void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
-        try {
-            RemoteDeathHandler handler = new RemoteDeathHandler(remote.asBinder());
-            remote.asBinder().linkToDeath(handler, 0 /* flags */);
-            mDeathHandlers.put(remote.asBinder(), handler);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Failed to link to death");
-            return;
-        }
+    void addFiltered(TransitionFilter filter, RemoteTransition remote) {
+        handleDeath(remote.asBinder(), null /* finishCallback */);
         mFilters.add(new Pair<>(filter, remote));
     }
 
-    void removeFiltered(IRemoteTransition remote) {
+    void removeFiltered(RemoteTransition remote) {
         boolean removed = false;
         for (int i = mFilters.size() - 1; i >= 0; --i) {
             if (mFilters.get(i).second == remote) {
@@ -83,8 +77,7 @@
             }
         }
         if (removed) {
-            RemoteDeathHandler handler = mDeathHandlers.remove(remote.asBinder());
-            remote.asBinder().unlinkToDeath(handler, 0 /* flags */);
+            unhandleDeath(remote.asBinder(), null /* finishCallback */);
         }
     }
 
@@ -98,7 +91,7 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        IRemoteTransition pendingRemote = mRequestedRemotes.get(transition);
+        RemoteTransition pendingRemote = mRequestedRemotes.get(transition);
         if (pendingRemote == null) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition %s doesn't have "
                     + "explicit remote, search filters for match for %s", transition, info);
@@ -120,21 +113,12 @@
 
         if (pendingRemote == null) return false;
 
-        final IRemoteTransition remote = pendingRemote;
-        final IBinder.DeathRecipient remoteDied = () -> {
-            Log.e(Transitions.TAG, "Remote transition died, finishing");
-            mMainExecutor.execute(() -> {
-                mRequestedRemotes.remove(transition);
-                finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
-            });
-        };
+        final RemoteTransition remote = pendingRemote;
         IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
             @Override
             public void onTransitionFinished(WindowContainerTransaction wct,
                     SurfaceControl.Transaction sct) {
-                if (remote.asBinder() != null) {
-                    remote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
-                }
+                unhandleDeath(remote.asBinder(), finishCallback);
                 mMainExecutor.execute(() -> {
                     if (sct != null) {
                         finishTransaction.merge(sct);
@@ -145,15 +129,11 @@
             }
         };
         try {
-            if (remote.asBinder() != null) {
-                remote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
-            }
-            remote.startAnimation(transition, info, startTransaction, cb);
+            handleDeath(remote.asBinder(), finishCallback);
+            remote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error running remote transition.", e);
-            if (remote.asBinder() != null) {
-                remote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
-            }
+            unhandleDeath(remote.asBinder(), finishCallback);
             mRequestedRemotes.remove(transition);
             mMainExecutor.execute(
                     () -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
@@ -165,7 +145,7 @@
     public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        final IRemoteTransition remote = mRequestedRemotes.get(mergeTarget);
+        final IRemoteTransition remote = mRequestedRemotes.get(mergeTarget).getRemoteTransition();
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Attempt merge %s into %s",
                 transition, remote);
         if (remote == null) return;
@@ -196,7 +176,7 @@
     @Nullable
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
             @Nullable TransitionRequestInfo request) {
-        IRemoteTransition remote = request.getRemoteTransition();
+        RemoteTransition remote = request.getRemoteTransition();
         if (remote == null) return null;
         mRequestedRemotes.put(transition, remote);
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "RemoteTransition directly requested"
@@ -204,14 +184,70 @@
         return new WindowContainerTransaction();
     }
 
+    private void handleDeath(@NonNull IBinder remote,
+            @Nullable Transitions.TransitionFinishCallback finishCallback) {
+        synchronized (mDeathHandlers) {
+            RemoteDeathHandler deathHandler = mDeathHandlers.get(remote);
+            if (deathHandler == null) {
+                deathHandler = new RemoteDeathHandler(remote);
+                try {
+                    remote.linkToDeath(deathHandler, 0 /* flags */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to link to death");
+                    return;
+                }
+                mDeathHandlers.put(remote, deathHandler);
+            }
+            deathHandler.addUser(finishCallback);
+        }
+    }
+
+    private void unhandleDeath(@NonNull IBinder remote,
+            @Nullable Transitions.TransitionFinishCallback finishCallback) {
+        synchronized (mDeathHandlers) {
+            RemoteDeathHandler deathHandler = mDeathHandlers.get(remote);
+            if (deathHandler == null) return;
+            deathHandler.removeUser(finishCallback);
+            if (deathHandler.getUserCount() == 0) {
+                if (!deathHandler.mPendingFinishCallbacks.isEmpty()) {
+                    throw new IllegalStateException("Unhandling death for binder that still has"
+                            + " pending finishCallback(s).");
+                }
+                remote.unlinkToDeath(deathHandler, 0 /* flags */);
+                mDeathHandlers.remove(remote);
+            }
+        }
+    }
+
     /** NOTE: binder deaths can alter the filter order */
     private class RemoteDeathHandler implements IBinder.DeathRecipient {
         private final IBinder mRemote;
+        private final ArrayList<Transitions.TransitionFinishCallback> mPendingFinishCallbacks =
+                new ArrayList<>();
+        private int mUsers = 0;
 
         RemoteDeathHandler(IBinder remote) {
             mRemote = remote;
         }
 
+        void addUser(@Nullable Transitions.TransitionFinishCallback finishCallback) {
+            if (finishCallback != null) {
+                mPendingFinishCallbacks.add(finishCallback);
+            }
+            ++mUsers;
+        }
+
+        void removeUser(@Nullable Transitions.TransitionFinishCallback finishCallback) {
+            if (finishCallback != null) {
+                mPendingFinishCallbacks.remove(finishCallback);
+            }
+            --mUsers;
+        }
+
+        int getUserCount() {
+            return mUsers;
+        }
+
         @Override
         @BinderThread
         public void binderDied() {
@@ -221,6 +257,16 @@
                         mFilters.remove(i);
                     }
                 }
+                for (int i = mRequestedRemotes.size() - 1; i >= 0; --i) {
+                    if (mRemote.equals(mRequestedRemotes.valueAt(i).asBinder())) {
+                        mRequestedRemotes.removeAt(i);
+                    }
+                }
+                for (int i = mPendingFinishCallbacks.size() - 1; i >= 0; --i) {
+                    mPendingFinishCallbacks.get(i).onTransitionFinished(
+                            null /* wct */, null /* wctCB */);
+                }
+                mPendingFinishCallbacks.clear();
             });
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index a13b03d..ada2ed2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -19,6 +19,7 @@
 import static android.hardware.HardwareBuffer.RGBA_8888;
 import static android.hardware.HardwareBuffer.USAGE_PROTECTED_CONTENT;
 import static android.util.RotationUtils.deltaRotation;
+import static android.view.WindowManagerPolicyConstants.SCREEN_FREEZE_LAYER_BASE;
 
 import static com.android.wm.shell.transition.DefaultTransitionHandler.startSurfaceAnimation;
 import static com.android.wm.shell.transition.Transitions.TAG;
@@ -81,19 +82,6 @@
  * </ul>
  */
 class ScreenRotationAnimation {
-
-    /** How much to multiply the policy's type layer, to reserve room
-     * for multiple windows of the same type and Z-ordering adjustment
-     * with TYPE_LAYER_OFFSET. */
-    static final int TYPE_LAYER_MULTIPLIER = 10000;
-    static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
-
-    /*
-     * Layers for screen rotation animation. We put these layers above
-     * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows.
-     */
-    private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
-
     static final int MAX_ANIMATION_DURATION = 10 * 1000;
 
     private final Context mContext;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
index bc42c6e..802d25f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
@@ -17,7 +17,7 @@
 package com.android.wm.shell.transition;
 
 import android.annotation.NonNull;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 
 import com.android.wm.shell.common.annotations.ExternalThread;
@@ -39,10 +39,10 @@
      * Registers a remote transition.
      */
     void registerRemote(@NonNull TransitionFilter filter,
-            @NonNull IRemoteTransition remoteTransition);
+            @NonNull RemoteTransition remoteTransition);
 
     /**
      * Unregisters a remote transition.
      */
-    void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
+    void unregisterRemote(@NonNull RemoteTransition remoteTransition);
 }
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..2720157 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
@@ -19,6 +19,7 @@
 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_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -39,8 +40,8 @@
 import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
-import android.window.IRemoteTransition;
 import android.window.ITransitionPlayer;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
@@ -54,6 +55,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 +115,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);
@@ -173,13 +176,13 @@
         return new ShellTransitions() {
             @Override
             public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
-                    @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
+                    @androidx.annotation.NonNull RemoteTransition remoteTransition) {
                 // Do nothing
             }
 
             @Override
             public void unregisterRemote(
-                    @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
+                    @androidx.annotation.NonNull RemoteTransition remoteTransition) {
                 // Do nothing
             }
         };
@@ -215,12 +218,12 @@
 
     /** Register a remote transition to be used when `filter` matches an incoming transition */
     public void registerRemote(@NonNull TransitionFilter filter,
-            @NonNull IRemoteTransition remoteTransition) {
+            @NonNull RemoteTransition remoteTransition) {
         mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
     }
 
     /** Unregisters a remote transition and all associated filters */
-    public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+    public void unregisterRemote(@NonNull RemoteTransition remoteTransition) {
         mRemoteTransitionHandler.removeFiltered(remoteTransition);
     }
 
@@ -228,7 +231,7 @@
     public static boolean isOpeningType(@WindowManager.TransitionType int type) {
         return type == TRANSIT_OPEN
                 || type == TRANSIT_TO_FRONT
-                || type == WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+                || type == TRANSIT_KEYGUARD_GOING_AWAY;
     }
 
     /** @return true if the transition was triggered by closing something vs opening something */
@@ -701,14 +704,14 @@
 
         @Override
         public void registerRemote(@NonNull TransitionFilter filter,
-                @NonNull IRemoteTransition remoteTransition) {
+                @NonNull RemoteTransition remoteTransition) {
             mMainExecutor.execute(() -> {
                 mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
             });
         }
 
         @Override
-        public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+        public void unregisterRemote(@NonNull RemoteTransition remoteTransition) {
             mMainExecutor.execute(() -> {
                 mRemoteTransitionHandler.removeFiltered(remoteTransition);
             });
@@ -735,7 +738,7 @@
 
         @Override
         public void registerRemote(@NonNull TransitionFilter filter,
-                @NonNull IRemoteTransition remoteTransition) {
+                @NonNull RemoteTransition remoteTransition) {
             executeRemoteCallWithTaskPermission(mTransitions, "registerRemote",
                     (transitions) -> {
                         transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
@@ -743,7 +746,7 @@
         }
 
         @Override
-        public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+        public void unregisterRemote(@NonNull RemoteTransition remoteTransition) {
             executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote",
                     (transitions) -> {
                         transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index d4b4e5d..7a17bb3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -17,11 +17,14 @@
 package com.android.wm.shell.flicker.helpers
 
 import android.app.Instrumentation
+import android.graphics.Rect
 import android.media.session.MediaController
 import android.media.session.MediaSessionManager
 import android.os.SystemClock
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
 import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow
@@ -85,6 +88,10 @@
 
         // Wait on WMHelper or simply wait for 3 seconds
         wmHelper?.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
+        // when entering pip, the dismiss button is visible at the start. to ensure the pip
+        // animation is complete, wait until the pip dismiss button is no longer visible. 
+        // b/176822698: dismiss-only state will be removed in the future
+        uiDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "dismiss")), FIND_TIMEOUT)
     }
 
     fun clickStartMediaSessionButton() {
@@ -113,26 +120,29 @@
         }
     }
 
+    private fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect {
+        val windowRegion = wmHelper.getWindowRegion(component)
+        require(!windowRegion.isEmpty) {
+            "Unable to find a PIP window in the current state"
+        }
+        return windowRegion.bounds
+    }
+
     /**
-     * Expands the pip window and dismisses it by clicking on the X button.
-     *
-     * Note, currently the View coordinates reported by the accessibility are relative to
-     * the window, so the correct coordinates need to be calculated
-     *
-     * For example, in a PIP window located at Rect(508, 1444 - 1036, 1741), the
-     * dismiss button coordinates are shown as Rect(650, 0 - 782, 132), with center in
-     * Point(716, 66), instead of Point(970, 1403)
-     *
-     * See b/179337864
+     * Taps the pip window and dismisses it by clicking on the X button.
      */
     fun closePipWindow(wmHelper: WindowManagerStateHelper) {
         if (isTelevision) {
             uiDevice.closeTvPipWindow()
         } else {
-            expandPipWindow(wmHelper)
-            val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss"))
-            requireNotNull(exitPipObject) { "PIP window dismiss button not found" }
-            val dismissButtonBounds = exitPipObject.visibleBounds
+            val windowRect = getWindowRect(wmHelper)
+            uiDevice.click(windowRect.centerX(), windowRect.centerY())
+            // search and interact with the dismiss button
+            val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
+            uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
+            val dismissPipObject = uiDevice.findObject(dismissSelector)
+                    ?: error("PIP window dismiss button not found")
+            val dismissButtonBounds = dismissPipObject.visibleBounds
             uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
         }
 
@@ -142,32 +152,29 @@
     }
 
     /**
-     * Click once on the PIP window to expand it
+     * Close the pip window by pressing the expand button
      */
-    fun expandPipWindow(wmHelper: WindowManagerStateHelper) {
-        val windowRegion = wmHelper.getWindowRegion(component)
-        require(!windowRegion.isEmpty) {
-            "Unable to find a PIP window in the current state"
-        }
-        val windowRect = windowRegion.bounds
+    fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) {
+        val windowRect = getWindowRect(wmHelper)
         uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        // Ensure WindowManagerService wait until all animations have completed
+        // search and interact with the expand button
+        val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button")
+        uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT)
+        val expandPipObject = uiDevice.findObject(expandSelector)
+                ?: error("PIP window expand button not found")
+        val expandButtonBounds = expandPipObject.visibleBounds
+        uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY())
+        wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
         wmHelper.waitForAppTransitionIdle()
-        mInstrumentation.uiAutomation.syncInputTransactions()
     }
 
     /**
-     * Double click on the PIP window to reopen to app
+     * Double click on the PIP window to expand it
      */
-    fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) {
-        val windowRegion = wmHelper.getWindowRegion(component)
-        require(!windowRegion.isEmpty) {
-            "Unable to find a PIP window in the current state"
-        }
-        val windowRect = windowRegion.bounds
+    fun doubleClickPipWindow(wmHelper: WindowManagerStateHelper) {
+        val windowRect = getWindowRect(wmHelper)
         uiDevice.click(windowRect.centerX(), windowRect.centerY())
         uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
         wmHelper.waitForAppTransitionIdle()
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
index 901b7a3..2d996ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
@@ -18,6 +18,7 @@
 
 import android.app.Instrumentation
 import android.content.ComponentName
+import android.content.res.Resources
 import com.android.wm.shell.flicker.testapp.Components
 
 class SplitScreenHelper(
@@ -30,6 +31,11 @@
         const val TEST_REPETITIONS = 1
         const val TIMEOUT_MS = 3_000L
 
+        // TODO: remove all legacy split screen flicker tests when legacy split screen is fully
+        //  deprecated.
+        fun isUsingLegacySplit(): Boolean =
+                Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useLegacySplit)
+
         fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper =
             SplitScreenHelper(instrumentation,
                 Components.SplitScreenActivity.LABEL,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index 508e939..18e0cc9e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -25,7 +25,7 @@
 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.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.navBarWindowIsVisible
@@ -50,7 +50,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
+@Group4
 class EnterSplitScreenDockActivity(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
index 12f3909..6080912 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
@@ -23,6 +23,7 @@
 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.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
@@ -43,6 +44,7 @@
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
 class EnterSplitScreenFromDetachedRecentTask(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index ac85c48..1dfc59e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -23,7 +23,7 @@
 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.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
@@ -49,7 +49,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
+@Group4
 class EnterSplitScreenLaunchToSide(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index 964af23..a278704 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
@@ -23,7 +23,7 @@
 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.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.canSplitScreen
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
@@ -51,7 +51,7 @@
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@Group1
+@Group4
 class EnterSplitScreenNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index af99fc4..ff34364 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.content.ComponentName
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -113,7 +112,7 @@
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
             super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
             super.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 7b4b71b..5fb6f1f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -104,7 +104,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.endRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index 666d259..3117693 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -39,6 +39,7 @@
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.After
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Test
 
@@ -56,6 +57,8 @@
 
     @Before
     open fun setup() {
+        // Only run legacy split tests when the system is using legacy split screen.
+        assumeTrue(SplitScreenHelper.isUsingLegacySplit())
         // Legacy split is having some issue with Shell transition, and will be deprecated soon.
         assumeFalse(isShellTransitionsEnabled())
         prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index ec0c73a..a7ac6a7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -28,7 +28,6 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
@@ -77,7 +76,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index d7f71a8..cd15051 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -129,7 +129,7 @@
     fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.endRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Test
     fun navBarLayerRotatesAndScales() =
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
deleted file mode 100644
index 39e89fb..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.platform.test.annotations.Postsubmit
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-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.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch and exit.
- * To run this test: `atest WMShellFlickerTests:EnterExitPipTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class EnterExitPipTest(
-    testSpec: FlickerTestParameter
-) : PipTransition(testSpec) {
-    private val testApp = FixedAppHelper(instrumentation)
-
-    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-        get() = buildTransition(eachRun = true) {
-            setup {
-                eachRun {
-                    testApp.launchViaIntent(wmHelper)
-                }
-            }
-            transitions {
-                // This will bring PipApp to fullscreen
-                pipApp.launchViaIntent(wmHelper)
-            }
-        }
-
-    @Presubmit
-    @Test
-    fun pipAppRemainInsideVisibleBounds() {
-        testSpec.assertWm {
-            coversAtMost(displayBounds, pipApp.component)
-        }
-    }
-
-    @Postsubmit
-    @Test
-    fun showBothAppWindowsThenHidePip() {
-        testSpec.assertWm {
-            // when the activity is STOPPING, sometimes it becomes invisible in an entry before
-            // the window, sometimes in the same entry. This occurs because we log 1x per frame
-            // thus we ignore activity here
-            isAppWindowVisible(testApp.component, ignoreActivity = true)
-                .isAppWindowOnTop(pipApp.component)
-                .then()
-                .isAppWindowInvisible(testApp.component)
-        }
-    }
-
-    @Presubmit
-    @Test
-    fun showBothAppLayersThenHidePip() {
-        testSpec.assertLayers {
-            isVisible(testApp.component)
-                .isVisible(pipApp.component)
-                .then()
-                .isInvisible(testApp.component)
-        }
-    }
-
-    @Presubmit
-    @Test
-    fun testAppCoversFullScreenWithPipOnDisplay() {
-        testSpec.assertLayersStart {
-            visibleRegion(testApp.component).coversExactly(displayBounds)
-            visibleRegion(pipApp.component).coversAtMost(displayBounds)
-        }
-    }
-
-    @Presubmit
-    @Test
-    fun pipAppCoversFullScreen() {
-        testSpec.assertLayersEnd {
-            visibleRegion(pipApp.component).coversExactly(displayBounds)
-        }
-    }
-
-    companion object {
-        @Parameterized.Parameters(name = "{0}")
-        @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
-        }
-    }
-}
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..046972d 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
@@ -23,8 +23,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 +34,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,14 +56,19 @@
 @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 {
                 pipApp.clickEnterPipButton(wmHelper)
-                pipApp.expandPipWindow(wmHelper)
             }
         }
 
+    /**
+     * Checks [pipApp] window remains visible throughout the animation
+     */
     @Presubmit
     @Test
     fun pipAppWindowAlwaysVisible() {
@@ -57,6 +77,9 @@
         }
     }
 
+    /**
+     * Checks [pipApp] layer remains visible throughout the animation
+     */
     @Presubmit
     @Test
     fun pipAppLayerAlwaysVisible() {
@@ -65,19 +88,89 @@
         }
     }
 
-    @FlakyTest
+    /**
+     * Checks that the pip app window remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
     @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
+     */
+    @Presubmit
+    @Test
+    fun pipLayerRemainInsideVisibleBounds() {
+        testSpec.assertLayers {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] always reduces during the animation
+     */
+    @Presubmit
+    @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
+     */
+    @Presubmit
+    @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
+     */
+    @Presubmit
+    @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/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 67ad322..097ccb8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -25,7 +25,11 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -38,8 +42,22 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test Pip with orientation changes.
- * To run this test: `atest WMShellFlickerTests:PipOrientationTest`
+ * Test entering pip while changing orientation (from app in landscape to pip window in portrait)
+ *
+ * To run this test: `atest EnterPipToOtherOrientationTest:EnterPipToOtherOrientationTest`
+ *
+ * Actions:
+ *     Launch [testApp] on a fixed portrait orientation
+ *     Launch [pipApp] on a fixed landscape orientation
+ *     Broadcast action [ACTION_ENTER_PIP] to enter 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)
@@ -53,6 +71,9 @@
     private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
     private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
 
+    /**
+     * Defines the transition used to run the test
+     */
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setupAndTeardown(this, configuration)
@@ -79,21 +100,41 @@
                 broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
                 wmHelper.waitFor { it.wmState.hasPipWindow() }
                 wmHelper.waitForAppTransitionIdle()
+                // during rotation the status bar becomes invisible and reappears at the end
+                wmHelper.waitForNavBarStatusBarVisible()
             }
         }
 
+    /**
+     * Checks that the [WindowManagerStateHelper.NAV_BAR_COMPONENT] has the correct position at
+     * the start and end of the transition
+     */
     @FlakyTest
     @Test
-    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+    override fun navBarLayerRotatesAndScales() =
+        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_90, Surface.ROTATION_0)
 
-    @FlakyTest
+    /**
+     * Checks that the [WindowManagerStateHelper.STATUS_BAR_COMPONENT] has the correct position at
+     * the start and end of the transition
+     */
+    @Presubmit
     @Test
-    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+    override fun statusBarLayerRotatesScales() =
+        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_90, Surface.ROTATION_0)
 
-    @FlakyTest
+    /**
+     * Checks that all parts of the screen are covered at the start and end of the transition
+     *
+     * TODO b/197726599 Prevents all states from being checked
+     */
+    @Presubmit
     @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    override fun entireScreenCovered() = testSpec.entireScreenCovered(allStates = false)
 
+    /**
+     * Checks [pipApp] window remains visible and on top throughout the transition
+     */
     @Presubmit
     @Test
     fun pipAppWindowIsAlwaysOnTop() {
@@ -102,40 +143,84 @@
         }
     }
 
+    /**
+     * Checks that [testApp] window is not visible at the start
+     */
     @Presubmit
     @Test
-    fun pipAppHidesTestApp() {
+    fun testAppWindowInvisibleOnStart() {
         testSpec.assertWmStart {
             isInvisible(testApp.component)
         }
     }
 
+    /**
+     * Checks that [testApp] window is visible at the end
+     */
     @Presubmit
     @Test
-    fun testAppWindowIsVisible() {
+    fun testAppWindowVisibleOnEnd() {
         testSpec.assertWmEnd {
             isVisible(testApp.component)
         }
     }
 
+    /**
+     * Checks that [testApp] layer is not visible at the start
+     */
     @Presubmit
     @Test
-    fun pipAppLayerHidesTestApp() {
+    fun testAppLayerInvisibleOnStart() {
         testSpec.assertLayersStart {
-            visibleRegion(pipApp.component).coversExactly(startingBounds)
             isInvisible(testApp.component)
         }
     }
 
+    /**
+     * Checks that [testApp] layer is visible at the end
+     */
     @Presubmit
     @Test
-    fun testAppLayerCoversFullScreen() {
+    fun testAppLayerVisibleOnEnd() {
         testSpec.assertLayersEnd {
-            visibleRegion(testApp.component).coversExactly(endingBounds)
+            isVisible(testApp.component)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] covers the full display area at the start of
+     * the transition
+     */
+    @Presubmit
+    @Test
+    fun pipAppLayerCoversFullScreenOnStart() {
+        testSpec.assertLayersStart {
+            visibleRegion(pipApp.component).coversExactly(startingBounds)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [testApp] plus the visible region of [pipApp]
+     * cover the full display area at the end of the transition
+     */
+    @Presubmit
+    @Test
+    fun testAppPlusPipLayerCoversFullScreenOnEnd() {
+        testSpec.assertLayersEnd {
+            val pipRegion = visibleRegion(pipApp.component).region
+            visibleRegion(testApp.component)
+                .plus(pipRegion)
+                .coversExactly(endingBounds)
         }
     }
 
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
new file mode 100644
index 0000000..faaaecb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Presubmit
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.traces.parser.toLayerName
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import org.junit.Test
+
+/**
+ * Base class for pip expand tests
+ */
+abstract class ExitPipToAppTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+    protected val testApp = FixedAppHelper(instrumentation)
+
+    /**
+     * Checks that the pip app window remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
+    @Test
+    open fun pipAppWindowRemainInsideVisibleBounds() {
+        testSpec.assertWm {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the pip app layer remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
+    @Test
+    open fun pipAppLayerRemainInsideVisibleBounds() {
+        testSpec.assertLayers {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks both app windows are visible at the start of the transition (with [pipApp] on top).
+     * Then, during the transition, [testApp] becomes invisible and [pipApp] remains visible
+     */
+    @Presubmit
+    @Test
+    open fun showBothAppWindowsThenHidePip() {
+        testSpec.assertWm {
+            // when the activity is STOPPING, sometimes it becomes invisible in an entry before
+            // the window, sometimes in the same entry. This occurs because we log 1x per frame
+            // thus we ignore activity here
+            isAppWindowVisible(testApp.component, ignoreActivity = true)
+                    .isAppWindowOnTop(pipApp.component)
+                    .then()
+                    .isAppWindowInvisible(testApp.component)
+                    .isAppWindowVisible(pipApp.component)
+        }
+    }
+
+    /**
+     * Checks both app layers are visible at the start of the transition. Then, during the
+     * transition, [testApp] becomes invisible and [pipApp] remains visible
+     */
+    @Presubmit
+    @Test
+    open fun showBothAppLayersThenHidePip() {
+        testSpec.assertLayers {
+            isVisible(testApp.component)
+                    .isVisible(pipApp.component)
+                    .then()
+                    .isInvisible(testApp.component)
+                    .isVisible(pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [testApp] plus the visible region of [pipApp]
+     * cover the full display area at the start of the transition
+     */
+    @Presubmit
+    @Test
+    open fun testPlusPipAppsCoverFullScreenAtStart() {
+        testSpec.assertLayersStart {
+            val pipRegion = visibleRegion(pipApp.component).region
+            visibleRegion(testApp.component)
+                    .plus(pipRegion)
+                    .coversExactly(displayBounds)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] covers the full display area at the end of
+     * the transition
+     */
+    @Presubmit
+    @Test
+    open fun pipAppCoversFullScreenAtEnd() {
+        testSpec.assertLayersEnd {
+            visibleRegion(pipApp.component).coversExactly(displayBounds)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] always expands during the animation
+     */
+    @Presubmit
+    @Test
+    open fun pipLayerExpands() {
+        val layerName = pipApp.component.toLayerName()
+        testSpec.assertLayers {
+            val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+            pipLayerList.zipWithNext { previous, current ->
+                current.visibleRegion.coversAtLeast(previous.visibleRegion.region)
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
similarity index 67%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 28b1028..3414031 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -20,15 +20,16 @@
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 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.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.startRotation
 import org.junit.Test
-import org.junit.runners.Parameterized
 
-abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+/**
+ * Base class for exiting pip (closing pip window) without returning to the app
+ */
+abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true) { configuration ->
             setup {
@@ -43,16 +44,28 @@
             }
         }
 
+    /**
+     * Checks that [pipApp] window is pinned and visible at the start and then becomes
+     * unpinned and invisible at the same moment, and remains unpinned and invisible
+     * until the end of the transition
+     */
     @Presubmit
     @Test
     open fun pipWindowBecomesInvisible() {
         testSpec.assertWm {
-            this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
-                .then()
-                .isAppWindowInvisible(pipApp.component)
+            this.invoke("hasPipWindow") {
+                it.isPinned(pipApp.component).isVisible(pipApp.component)
+            }.then().invoke("!hasPipWindow") {
+                it.isNotPinned(pipApp.component).isInvisible(pipApp.component)
+            }
         }
     }
 
+    /**
+     * Checks that [pipApp] and [LAUNCHER_COMPONENT] layers are visible at the start
+     * of the transition. Then [pipApp] layer becomes invisible, and remains invisible
+     * until the end of the transition
+     */
     @Presubmit
     @Test
     open fun pipLayerBecomesInvisible() {
@@ -65,6 +78,10 @@
         }
     }
 
+    /**
+     * Checks that the focus changes between the [pipApp] window and the launcher when
+     * closing the pip window
+     */
     @FlakyTest(bugId = 151179149)
     @Test
     open fun focusChanges() {
@@ -72,14 +89,4 @@
             this.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
         }
     }
-
-    companion object {
-        @Parameterized.Parameters(name = "{0}")
-        @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                    repetitions = 5)
-        }
-    }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
new file mode 100644
index 0000000..fa100b5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.flicker.pip
+
+import android.view.Surface
+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.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toWindowName
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test expanding a pip window back to full screen via the expand button
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipViaExpandButtonClickTest`
+ *
+ * Actions:
+ *     Launch an app in pip mode [pipApp],
+ *     Launch another full screen mode [testApp]
+ *     Expand [pipApp] app to full screen by clicking on the pip window and
+ *     then on the expand button
+ *
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExitPipViaExpandButtonClickTest(
+    testSpec: FlickerTestParameter
+) : ExitPipToAppTransition(testSpec) {
+
+    /**
+     * Defines the transition used to run the test
+     */
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition(eachRun = true) {
+            setup {
+                eachRun {
+                    // launch an app behind the pip one
+                    testApp.launchViaIntent(wmHelper)
+                }
+            }
+            transitions {
+                // This will bring PipApp to fullscreen
+                pipApp.expandPipWindowToApp(wmHelper)
+                // Wait until the other app is no longer visible
+                wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+            }
+        }
+
+    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> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                    supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
new file mode 100644
index 0000000..617ef22
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toWindowName
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test expanding a pip window back to full screen via an intent
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipViaIntentTest`
+ *
+ * Actions:
+ *     Launch an app in pip mode [pipApp],
+ *     Launch another full screen mode [testApp]
+ *     Expand [pipApp] app to full screen via an intent
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited from [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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransition(testSpec) {
+
+    /**
+     * Defines the transition used to run the test
+     */
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition(eachRun = true) {
+            setup {
+                eachRun {
+                    // launch an app behind the pip one
+                    testApp.launchViaIntent(wmHelper)
+                }
+            }
+            transitions {
+                // This will bring PipApp to fullscreen
+                pipApp.launchViaIntent(wmHelper)
+                // Wait until the other app is no longer visible
+                wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+            }
+        }
+
+    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> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
new file mode 100644
index 0000000..e3d099f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+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.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test closing a pip window via the dismiss button
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipWithDismissButtonTest`
+ *
+ * Actions:
+ *     Launch an app in pip mode [pipApp],
+ *     Click on the pip window
+ *     Click on dismiss button and wait window disappear
+ *
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExitPipWithDismissButtonTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            transitions {
+                pipApp.closePipWindow(wmHelper)
+            }
+        }
+
+    @Postsubmit
+    @Test
+    override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
+
+    @Postsubmit
+    @Test
+    override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
+
+    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> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+                            repetitions = 5)
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
similarity index 62%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 356ec94..2cdfc2b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -22,6 +22,7 @@
 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.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.startRotation
@@ -33,24 +34,40 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipCloseWithSwipe`
+ * Test closing a pip window by swiping it to the bottom-center of the screen
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipWithSwipeDownTest`
+ *
+ * Actions:
+ *     Launch an app in pip mode [pipApp],
+ *     Swipe the pip window to the bottom-center of the screen and wait it disappear
+ *
+ * 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)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group3
-class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
+class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) {
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-        get() = {
-            super.transition(this, it)
+        get() = { args ->
+            super.transition(this, args)
             transitions {
                 val pipRegion = wmHelper.getWindowRegion(pipApp.component).bounds
                 val pipCenterX = pipRegion.centerX()
                 val pipCenterY = pipRegion.centerY()
                 val displayCenterX = device.displayWidth / 2
-                device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 5)
+                device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 10)
+                wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
+                wmHelper.waitForWindowSurfaceDisappeared(pipApp.component)
+                wmHelper.waitForAppTransitionIdle()
             }
         }
 
@@ -90,4 +107,20 @@
     @Presubmit
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    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> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+                            repetitions = 20)
+        }
+    }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
new file mode 100644
index 0000000..89b2c40
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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
+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.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
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test expanding a pip window by double clicking it
+ *
+ * To run this test: `atest WMShellFlickerTests:ExpandPipOnDoubleClickTest`
+ *
+ * Actions:
+ *     Launch an app in pip mode [pipApp],
+ *     Expand [pipApp] app to its maximum pip size by double clicking on it
+ *
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition(eachRun = true) {
+            transitions {
+                pipApp.doubleClickPipWindow(wmHelper)
+            }
+        }
+
+    /**
+     * Checks that the pip app window remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
+    @Test
+    fun pipWindowRemainInsideVisibleBounds() {
+        testSpec.assertWm {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the pip app layer remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
+    @Test
+    fun pipLayerRemainInsideVisibleBounds() {
+        testSpec.assertLayers {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks [pipApp] window remains visible throughout the animation
+     */
+    @Postsubmit
+    @Test
+    fun pipWindowIsAlwaysVisible() {
+        testSpec.assertWm {
+            isAppWindowVisible(pipApp.component)
+        }
+    }
+
+    /**
+     * Checks [pipApp] layer remains visible throughout the animation
+     */
+    @Presubmit
+    @Test
+    fun pipLayerIsAlwaysVisible() {
+        testSpec.assertLayers {
+            isVisible(pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] always expands during the animation
+     */
+    @Presubmit
+    @Test
+    fun pipLayerExpands() {
+        val layerName = pipApp.component.toLayerName()
+        testSpec.assertLayers {
+            val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+            pipLayerList.zipWithNext { previous, current ->
+                current.visibleRegion.coversAtLeast(previous.visibleRegion.region)
+            }
+        }
+    }
+
+    /**
+     * Checks [pipApp] window remains pinned throughout the animation
+     */
+    @Presubmit
+    @Test
+    fun windowIsAlwaysPinned() {
+        testSpec.assertWm {
+            this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
+        }
+    }
+
+    /**
+     * Checks [pipApp] layer remains visible throughout the animation
+     */
+    @Presubmit
+    @Test
+    fun launcherIsAlwaysVisible() {
+        testSpec.assertLayers {
+            isVisible(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks that the focus doesn't change between windows during the transition
+     */
+    @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> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+                            repetitions = 5)
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
new file mode 100644
index 0000000..0ab857d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.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.wm.shell.flicker.pip
+
+import android.view.Surface
+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.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.traces.RegionSubject
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip movement with Launcher shelf height change (decrease).
+ *
+ * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest`
+ *
+ * Actions:
+ *     Launch [pipApp] in pip mode
+ *     Launch [testApp]
+ *     Press home
+ *     Check if pip window moves down (visually)
+ *
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class MovePipDownShelfHeightChangeTest(
+    testSpec: FlickerTestParameter
+) : MovePipShelfHeightTransition(testSpec) {
+    /**
+     * Defines the transition used to run the test
+     */
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition(eachRun = false) {
+            teardown {
+                eachRun {
+                    testApp.launchViaIntent(wmHelper)
+                }
+                test {
+                    testApp.exit(wmHelper)
+                }
+            }
+            transitions {
+                taplInstrumentation.pressHome()
+            }
+        }
+
+    override fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) {
+        current.isHigherOrEqual(previous.region)
+    }
+
+    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> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                    supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
new file mode 100644
index 0000000..ed04fc9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
@@ -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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Presubmit
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.traces.RegionSubject
+import com.android.server.wm.traces.parser.toLayerName
+import com.android.server.wm.traces.parser.toWindowName
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import org.junit.Test
+
+/**
+ * Base class for pip tests with Launcher shelf height change
+ */
+abstract class MovePipShelfHeightTransition(
+    testSpec: FlickerTestParameter
+) : PipTransition(testSpec) {
+    protected val taplInstrumentation = LauncherInstrumentation()
+    protected val testApp = FixedAppHelper(instrumentation)
+
+    /**
+     * Checks if the window movement direction is valid
+     */
+    protected abstract fun assertRegionMovement(previous: RegionSubject, current: RegionSubject)
+
+    /**
+     * Checks [pipApp] window remains visible throughout the animation
+     */
+    @Presubmit
+    @Test
+    open fun pipWindowIsAlwaysVisible() {
+        testSpec.assertWm {
+            isAppWindowVisible(pipApp.component)
+        }
+    }
+
+    /**
+     * Checks [pipApp] layer remains visible throughout the animation
+     */
+    @Presubmit
+    @Test
+    open fun pipLayerIsAlwaysVisible() {
+        testSpec.assertLayers {
+            isVisible(pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the pip app window remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
+    @Test
+    open fun pipWindowRemainInsideVisibleBounds() {
+        testSpec.assertWm {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the pip app layer remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Presubmit
+    @Test
+    open fun pipLayerRemainInsideVisibleBounds() {
+        testSpec.assertLayers {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] always moves in the correct direction
+     * during the animation.
+     */
+    @Presubmit
+    @Test
+    open fun pipWindowMoves() {
+        val windowName = pipApp.component.toWindowName()
+        testSpec.assertWm {
+            val pipWindowList = this.windowStates { it.name.contains(windowName) && it.isVisible }
+            pipWindowList.zipWithNext { previous, current ->
+                assertRegionMovement(previous.frame, current.frame)
+            }
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] always moves up during the animation
+     */
+    @Presubmit
+    @Test
+    open fun pipLayerMoves() {
+        val layerName = pipApp.component.toLayerName()
+        testSpec.assertLayers {
+            val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+            pipLayerList.zipWithNext { previous, current ->
+                assertRegionMovement(previous.visibleRegion, current.visibleRegion)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
new file mode 100644
index 0000000..e507edf
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.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.wm.shell.flicker.pip
+
+import android.view.Surface
+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.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.traces.RegionSubject
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip movement with Launcher shelf height change (increase).
+ *
+ * To run this test: `atest WMShellFlickerTests:MovePipUpShelfHeightChangeTest`
+ *
+ * Actions:
+ *     Launch [pipApp] in pip mode
+ *     Press home
+ *     Launch [testApp]
+ *     Check if pip window moves up (visually)
+ *
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class MovePipUpShelfHeightChangeTest(
+    testSpec: FlickerTestParameter
+) : MovePipShelfHeightTransition(testSpec) {
+    /**
+     * Defines the transition used to run the test
+     */
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition(eachRun = false) {
+            teardown {
+                eachRun {
+                    taplInstrumentation.pressHome()
+                }
+                test {
+                    testApp.exit(wmHelper)
+                }
+            }
+            transitions {
+                testApp.launchViaIntent(wmHelper)
+            }
+        }
+
+    override fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) {
+        current.isLowerOrEqual(previous.region)
+    }
+
+    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> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
deleted file mode 100644
index 1c5d77f..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-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.annotation.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipCloseWithDismissButton`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
-    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-        get() = {
-            super.transition(this, it)
-            transitions {
-                pipApp.closePipWindow(wmHelper)
-            }
-        }
-
-    @FlakyTest
-    @Test
-    override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
-
-    @FlakyTest
-    @Test
-    override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 5719413..9dad336 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -22,7 +22,7 @@
 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.Group3
+import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
@@ -43,7 +43,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
+@Group4
 class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
     private val imeApp = ImeAppHelper(instrumentation)
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index c09fdc2..d6030401 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -23,15 +23,20 @@
 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.Group3
+import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.helpers.ImeAppHelper
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,11 +51,19 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
+@Group4
 class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
     private val imeApp = ImeAppHelper(instrumentation)
     private val testApp = FixedAppHelper(instrumentation)
 
+    @Before
+    open fun setup() {
+        // Only run legacy split tests when the system is using legacy split screen.
+        assumeTrue(SplitScreenHelper.isUsingLegacySplit())
+        // Legacy split is having some issue with Shell transition, and will be deprecated soon.
+        assumeFalse(isShellTransitionsEnabled())
+    }
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             withTestName { testSpec.name }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index e0ec757..08d5209 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -23,7 +23,7 @@
 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.Group3
+import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.entireScreenCovered
@@ -41,17 +41,32 @@
 
 /**
  * Test Pip Stack in bounds after rotations.
+ *
  * To run this test: `atest WMShellFlickerTests:PipRotationTest`
+ *
+ * Actions:
+ *     Launch a [pipApp] in pip mode
+ *     Launch another app [fixedApp] (appears below pip)
+ *     Rotate the screen from [testSpec.config.startRotation] to [testSpec.config.endRotation]
+ *     (usually, 0->90 and 90->0)
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited from [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)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
+@Group4
 class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
     private val fixedApp = FixedAppHelper(instrumentation)
-    private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
-    private val endingBounds = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
+    private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+    private val screenBoundsEnd = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
 
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = false) { configuration ->
@@ -66,49 +81,108 @@
             transitions {
                 setRotation(configuration.endRotation)
             }
-            teardown {
-                eachRun {
-                    setRotation(Surface.ROTATION_0)
-                }
-            }
         }
 
+    /**
+     * Checks that all parts of the screen are covered at the start and end of the transition
+     */
     @Presubmit
     @Test
-    override fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
-        testSpec.config.endRotation, allStates = false)
+    override fun entireScreenCovered() = testSpec.entireScreenCovered()
 
+    /**
+     * Checks the position of the navigation bar at the start and end of the transition
+     */
     @FlakyTest
     @Test
     override fun navBarLayerRotatesAndScales() =
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
             testSpec.config.endRotation)
 
+    /**
+     * Checks the position of the status bar at the start and end of the transition
+     */
     @Presubmit
     @Test
     override fun statusBarLayerRotatesScales() =
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
             testSpec.config.endRotation)
 
+    /**
+     * Checks that [fixedApp] layer is within [screenBoundsStart] at the start of the transition
+     */
     @Presubmit
     @Test
     fun appLayerRotates_StartingBounds() {
         testSpec.assertLayersStart {
-            visibleRegion(fixedApp.component).coversExactly(startingBounds)
-            visibleRegion(pipApp.component).coversAtMost(startingBounds)
+            visibleRegion(fixedApp.component).coversExactly(screenBoundsStart)
         }
     }
 
+    /**
+     * Checks that [fixedApp] layer is within [screenBoundsEnd] at the end of the transition
+     */
     @Presubmit
     @Test
     fun appLayerRotates_EndingBounds() {
         testSpec.assertLayersEnd {
-            visibleRegion(fixedApp.component).coversExactly(endingBounds)
-            visibleRegion(pipApp.component).coversAtMost(endingBounds)
+            visibleRegion(fixedApp.component).coversExactly(screenBoundsEnd)
+        }
+    }
+
+    /**
+     * Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition
+     */
+    @Presubmit
+    @Test
+    fun pipLayerRotates_StartingBounds() {
+        testSpec.assertLayersStart {
+            visibleRegion(pipApp.component).coversAtMost(screenBoundsStart)
+        }
+    }
+
+    /**
+     * Checks that [pipApp] layer is within [screenBoundsEnd] at the end of the transition
+     */
+    @Presubmit
+    @Test
+    fun pipLayerRotates_EndingBounds() {
+        testSpec.assertLayersEnd {
+            visibleRegion(pipApp.component).coversAtMost(screenBoundsEnd)
+        }
+    }
+
+    /**
+     * Ensure that the [pipApp] window does not obscure the [fixedApp] at the start of the
+     * transition
+     */
+    @Presubmit
+    @Test
+    fun pipIsAboveFixedAppWindow_Start() {
+        testSpec.assertWmStart {
+            isAboveWindow(pipApp.component, fixedApp.component)
+        }
+    }
+
+    /**
+     * Ensure that the [pipApp] window does not obscure the [fixedApp] at the end of the
+     * transition
+     */
+    @Presubmit
+    @Test
+    fun pipIsAboveFixedAppWindow_End() {
+        testSpec.assertWmEnd {
+            isAboveWindow(pipApp.component, fixedApp.component)
         }
     }
 
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
deleted file mode 100644
index 914bc8b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
+++ /dev/null
@@ -1,98 +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.wm.shell.flicker.pip
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.launcher3.tapl.LauncherInstrumentation
-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.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.google.common.truth.Truth
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip movement with Launcher shelf height change.
- * To run this test: `atest WMShellFlickerTests:PipShelfHeightTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class PipShelfHeightTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
-    private val taplInstrumentation = LauncherInstrumentation()
-    private val testApp = FixedAppHelper(instrumentation)
-
-    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-        get() = buildTransition(eachRun = false) {
-            teardown {
-                eachRun {
-                    taplInstrumentation.pressHome()
-                }
-                test {
-                    testApp.exit(wmHelper)
-                }
-            }
-            transitions {
-                testApp.launchViaIntent(wmHelper)
-            }
-        }
-
-    @Presubmit
-    @Test
-    fun pipAlwaysVisible() = testSpec.assertWm { this.isAppWindowVisible(pipApp.component) }
-
-    @Presubmit
-    @Test
-    fun pipLayerInsideDisplay() {
-        testSpec.assertLayersStart {
-            visibleRegion(pipApp.component).coversAtMost(displayBounds)
-        }
-    }
-
-    @Presubmit
-    @Test
-    fun pipWindowMovesUp() = testSpec.assertWmEnd {
-        val initialState = this.trace?.first()?.wmState
-            ?: error("Trace should not be empty")
-        val startPos = initialState.pinnedWindows.first().frame
-        val currPos = this.wmState.pinnedWindows.first().frame
-        val subject = Truth.assertWithMessage("Pip should have moved up")
-        subject.that(currPos.top).isGreaterThan(startPos.top)
-        subject.that(currPos.bottom).isGreaterThan(startPos.bottom)
-        subject.that(currPos.left).isEqualTo(startPos.left)
-        subject.that(currPos.right).isEqualTo(startPos.right)
-    }
-
-    companion object {
-        @Parameterized.Parameters(name = "{0}")
-        @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
deleted file mode 100644
index 5abcf39..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.view.Surface
-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.LAUNCHER_COMPONENT
-import com.android.server.wm.flicker.annotation.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.startRotation
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipToAppTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
-    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-        get() = buildTransition(eachRun = true) { configuration ->
-            setup {
-                eachRun {
-                    this.setRotation(configuration.startRotation)
-                }
-            }
-            teardown {
-                eachRun {
-                    this.setRotation(Surface.ROTATION_0)
-                }
-            }
-            transitions {
-                pipApp.expandPipWindowToApp(wmHelper)
-            }
-        }
-
-    @FlakyTest
-    @Test
-    fun appReplacesPipWindow() {
-        testSpec.assertWm {
-            this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
-                .isAppWindowOnTop(pipApp.component)
-                .then()
-                .invoke("hasNotPipWindow") { it.isNotPinned(pipApp.component) }
-                .isAppWindowOnTop(pipApp.component)
-        }
-    }
-
-    @FlakyTest
-    @Test
-    fun appReplacesPipLayer() {
-        testSpec.assertLayers {
-            this.isVisible(pipApp.component)
-                .isVisible(LAUNCHER_COMPONENT)
-                .then()
-                .isVisible(pipApp.component)
-                .isInvisible(LAUNCHER_COMPONENT)
-        }
-    }
-
-    @FlakyTest
-    @Test
-    fun testAppCoversFullScreen() {
-        testSpec.assertLayersStart {
-            visibleRegion(pipApp.component).coversExactly(displayBounds)
-        }
-    }
-
-    @FlakyTest(bugId = 151179149)
-    @Test
-    fun focusChanges() {
-        testSpec.assertEventLog {
-            this.focusChanges("NexusLauncherActivity",
-                    pipApp.launcherName, "NexusLauncherActivity")
-        }
-    }
-
-    companion object {
-        @Parameterized.Parameters(name = "{0}")
-        @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                            repetitions = 5)
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index ca80d18..ce89fb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -187,6 +187,5 @@
 
     @Presubmit
     @Test
-    open fun entireScreenCovered() =
-        testSpec.entireScreenCovered(testSpec.config.startRotation, Surface.ROTATION_0)
+    open fun entireScreenCovered() = testSpec.entireScreenCovered()
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index e7b6197..d6dbc36 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -22,7 +22,7 @@
 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.Group3
+import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
@@ -43,7 +43,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
+@Group4
 class SetRequestedOrientationWhilePinnedTest(
     testSpec: FlickerTestParameter
 ) : PipTransition(testSpec) {
@@ -144,9 +144,7 @@
 
     @FlakyTest
     @Test
-    override fun entireScreenCovered() {
-        super.entireScreenCovered()
-    }
+    override fun entireScreenCovered() = super.entireScreenCovered()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 3e3195f..b0312e6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -869,6 +869,35 @@
         assertNotNull(mBubbleData.getOverflowBubbleWithKey(mBubbleA2.getKey()));
     }
 
+    /**
+     * Verifies that after the stack is collapsed with the overflow selected, it will select
+     * the top bubble upon next expansion.
+     */
+    @Test
+    public void test_collapseWithOverflowSelected_nextExpansion() {
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        sendUpdatedEntryAtTime(mEntryA2, 2000);
+        mBubbleData.setExpanded(true);
+
+        mBubbleData.setListener(mListener);
+
+        // Select the overflow
+        mBubbleData.setShowingOverflow(true);
+        mBubbleData.setSelectedBubble(mBubbleData.getOverflow());
+        verifyUpdateReceived();
+        assertSelectionChangedTo(mBubbleData.getOverflow());
+
+        // Collapse
+        mBubbleData.setExpanded(false);
+        verifyUpdateReceived();
+        assertSelectionNotChanged();
+
+        // Expand (here we should select the new bubble)
+        mBubbleData.setExpanded(true);
+        verifyUpdateReceived();
+        assertSelectionChangedTo(mBubbleA2);
+    }
+
     private void verifyUpdateReceived() {
         verify(mListener).applyUpdate(mUpdateCaptor.capture());
         reset(mListener);
@@ -902,7 +931,7 @@
         assertWithMessage("selectionChanged").that(update.selectionChanged).isFalse();
     }
 
-    private void assertSelectionChangedTo(Bubble bubble) {
+    private void assertSelectionChangedTo(BubbleViewProvider bubble) {
         BubbleData.Update update = mUpdateCaptor.getValue();
         assertWithMessage("selectionChanged").that(update.selectionChanged).isTrue();
         assertWithMessage("selectedBubble").that(update.selectedBubble).isEqualTo(bubble);
@@ -925,7 +954,6 @@
         assertThat(update.overflowBubbles).isEqualTo(bubbles);
     }
 
-
     private BubbleEntry createBubbleEntry(int userId, String notifKey, String packageName,
             NotificationListenerService.Ranking ranking) {
         return createBubbleEntry(userId, notifKey, packageName, ranking, 1000);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
index 1eba3c2..9732a88 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import android.annotation.SuppressLint;
 import android.content.res.Configuration;
@@ -41,7 +42,6 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Spy;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -49,26 +49,26 @@
 
     private int mDisplayWidth = 500;
     private int mDisplayHeight = 1000;
-    private int mExpandedViewPadding = 10;
 
     private Runnable mOnBubbleAnimatedOutAction = mock(Runnable.class);
-    @Spy
     ExpandedAnimationController mExpandedController;
 
     private int mStackOffset;
     private PointF mExpansionPoint;
+    private BubblePositioner mPositioner;
 
     @SuppressLint("VisibleForTests")
     @Before
     public void setUp() throws Exception {
         super.setUp();
 
-        BubblePositioner positioner = new BubblePositioner(getContext(), mock(WindowManager.class));
-        positioner.updateInternal(Configuration.ORIENTATION_PORTRAIT,
+        mPositioner = new BubblePositioner(getContext(), mock(WindowManager.class));
+        mPositioner.updateInternal(Configuration.ORIENTATION_PORTRAIT,
                 Insets.of(0, 0, 0, 0),
                 new Rect(0, 0, mDisplayWidth, mDisplayHeight));
-        mExpandedController = new ExpandedAnimationController(positioner, mExpandedViewPadding,
+        mExpandedController = new ExpandedAnimationController(mPositioner,
                 mOnBubbleAnimatedOutAction);
+        spyOn(mExpandedController);
 
         addOneMoreThanBubbleLimitBubbles();
         mLayout.setActiveController(mExpandedController);
@@ -141,13 +141,16 @@
 
     /** Check that children are in the correct positions for being expanded. */
     private void testBubblesInCorrectExpandedPositions() {
+        boolean onLeft = mPositioner.isStackOnLeft(mExpansionPoint);
         // Check all the visible bubbles to see if they're in the right place.
         for (int i = 0; i < mLayout.getChildCount(); i++) {
-            float expectedPosition = mExpandedController.getBubbleXOrYForOrientation(i);
-            assertEquals(expectedPosition,
+            PointF expectedPosition = mPositioner.getExpandedBubbleXY(i,
+                    mLayout.getChildCount(),
+                    onLeft);
+            assertEquals(expectedPosition.x,
                     mLayout.getChildAt(i).getTranslationX(),
                     2f);
-            assertEquals(expectedPosition,
+            assertEquals(expectedPosition.y,
                     mLayout.getChildAt(i).getTranslationY(), 2f);
         }
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index ef046d4..b888450 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -58,7 +58,7 @@
         mT = mock(SurfaceControl.Transaction.class);
         mMock = mock(IInputMethodManager.class);
         mExecutor = spy(Runnable::run);
-        mPerDisplay = new DisplayImeController(null, null, mExecutor, new TransactionPool() {
+        mPerDisplay = new DisplayImeController(null, null, null, mExecutor, new TransactionPool() {
             @Override
             public SurfaceControl.Transaction acquire() {
                 return mT;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
new file mode 100644
index 0000000..b66c2b4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.IWindowManager;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.TestShellExecutor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+public class DisplayInsetsControllerTest {
+
+    private static final int SECOND_DISPLAY = DEFAULT_DISPLAY + 10;
+
+    @Mock
+    private IWindowManager mWm;
+    @Mock
+    private DisplayController mDisplayController;
+    private DisplayInsetsController mController;
+    private SparseArray<IDisplayWindowInsetsController> mInsetsControllersByDisplayId;
+    private TestShellExecutor mExecutor;
+
+    private ArgumentCaptor<Integer> mDisplayIdCaptor;
+    private ArgumentCaptor<IDisplayWindowInsetsController> mInsetsControllerCaptor;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mExecutor = new TestShellExecutor();
+        mInsetsControllersByDisplayId = new SparseArray<>();
+        mDisplayIdCaptor =  ArgumentCaptor.forClass(Integer.class);
+        mInsetsControllerCaptor = ArgumentCaptor.forClass(IDisplayWindowInsetsController.class);
+        mController = new DisplayInsetsController(mWm, mDisplayController, mExecutor);
+        addDisplay(DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testOnDisplayAdded_setsDisplayWindowInsetsControllerOnWMService()
+            throws RemoteException {
+        addDisplay(SECOND_DISPLAY);
+
+        verify(mWm).setDisplayWindowInsetsController(eq(SECOND_DISPLAY), notNull());
+    }
+
+    @Test
+    public void testOnDisplayRemoved_unsetsDisplayWindowInsetsControllerInWMService()
+            throws RemoteException {
+        addDisplay(SECOND_DISPLAY);
+        removeDisplay(SECOND_DISPLAY);
+
+        verify(mWm).setDisplayWindowInsetsController(SECOND_DISPLAY, null);
+    }
+
+    @Test
+    public void testPerDisplayListenerCallback() throws RemoteException {
+        TrackedListener defaultListener = new TrackedListener();
+        TrackedListener secondListener = new TrackedListener();
+        addDisplay(SECOND_DISPLAY);
+        mController.addInsetsChangedListener(DEFAULT_DISPLAY, defaultListener);
+        mController.addInsetsChangedListener(SECOND_DISPLAY, secondListener);
+
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).topFocusedWindowChanged(null);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsChanged(null);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsControlChanged(null, null);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).showInsets(0, false);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).hideInsets(0, false);
+        mExecutor.flushAll();
+
+        assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
+        assertTrue(defaultListener.insetsChangedCount == 1);
+        assertTrue(defaultListener.insetsControlChangedCount == 1);
+        assertTrue(defaultListener.showInsetsCount == 1);
+        assertTrue(defaultListener.hideInsetsCount == 1);
+
+        assertTrue(secondListener.topFocusedWindowChangedCount == 0);
+        assertTrue(secondListener.insetsChangedCount == 0);
+        assertTrue(secondListener.insetsControlChangedCount == 0);
+        assertTrue(secondListener.showInsetsCount == 0);
+        assertTrue(secondListener.hideInsetsCount == 0);
+
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).topFocusedWindowChanged(null);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsChanged(null);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsControlChanged(null, null);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).showInsets(0, false);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).hideInsets(0, false);
+        mExecutor.flushAll();
+
+        assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
+        assertTrue(defaultListener.insetsChangedCount == 1);
+        assertTrue(defaultListener.insetsControlChangedCount == 1);
+        assertTrue(defaultListener.showInsetsCount == 1);
+        assertTrue(defaultListener.hideInsetsCount == 1);
+
+        assertTrue(secondListener.topFocusedWindowChangedCount == 1);
+        assertTrue(secondListener.insetsChangedCount == 1);
+        assertTrue(secondListener.insetsControlChangedCount == 1);
+        assertTrue(secondListener.showInsetsCount == 1);
+        assertTrue(secondListener.hideInsetsCount == 1);
+    }
+
+    private void addDisplay(int displayId) throws RemoteException {
+        mController.onDisplayAdded(displayId);
+        verify(mWm, times(mInsetsControllersByDisplayId.size() + 1))
+                .setDisplayWindowInsetsController(mDisplayIdCaptor.capture(),
+                        mInsetsControllerCaptor.capture());
+        List<Integer> displayIds = mDisplayIdCaptor.getAllValues();
+        List<IDisplayWindowInsetsController> insetsControllers =
+                mInsetsControllerCaptor.getAllValues();
+        for (int i = 0; i < displayIds.size(); i++) {
+            mInsetsControllersByDisplayId.put(displayIds.get(i), insetsControllers.get(i));
+        }
+    }
+
+    private void removeDisplay(int displayId) {
+        mController.onDisplayRemoved(displayId);
+        mInsetsControllersByDisplayId.remove(displayId);
+    }
+
+    private static class TrackedListener implements
+            DisplayInsetsController.OnInsetsChangedListener {
+        int topFocusedWindowChangedCount = 0;
+        int insetsChangedCount = 0;
+        int insetsControlChangedCount = 0;
+        int showInsetsCount = 0;
+        int hideInsetsCount = 0;
+
+        @Override
+        public void topFocusedWindowChanged(String packageName) {
+            topFocusedWindowChangedCount++;
+        }
+
+        @Override
+        public void insetsChanged(InsetsState insetsState) {
+            insetsChangedCount++;
+        }
+
+        @Override
+        public void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls) {
+            insetsControlChangedCount++;
+        }
+
+        @Override
+        public void showInsets(int types, boolean fromIme) {
+            showInsetsCount++;
+        }
+
+        @Override
+        public void hideInsets(int types, boolean fromIme) {
+            hideInsetsCount++;
+        }
+    }
+}
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 3dc0465..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
@@ -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/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 698315a..c456c7d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -22,6 +22,7 @@
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 
 import androidx.test.annotation.UiThreadTest;
@@ -59,7 +60,7 @@
     @Test
     @UiThreadTest
     public void testInitRelease() {
-        mSplitWindowManager.init(mSplitLayout);
+        mSplitWindowManager.init(mSplitLayout, new InsetsState());
         assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
         mSplitWindowManager.release();
         assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
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 1a70f76..734b97b 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
@@ -65,6 +65,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.InstanceId;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -96,6 +97,9 @@
     @Mock
     private SplitScreenController mSplitScreenStarter;
 
+    @Mock
+    private InstanceId mLoggerSessionId;
+
     private DisplayLayout mLandscapeDisplayLayout;
     private DisplayLayout mPortraitDisplayLayout;
     private Insets mInsets;
@@ -201,7 +205,7 @@
     @Test
     public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() {
         setRunningTask(mHomeTask);
-        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
 
@@ -213,7 +217,7 @@
     @Test
     public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
         setRunningTask(mFullscreenAppTask);
-        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
@@ -230,7 +234,7 @@
     @Test
     public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
         setRunningTask(mFullscreenAppTask);
-        mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
+        mPolicy.start(mPortraitDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
@@ -248,7 +252,7 @@
     public void testDragAppOverSplitApp_expectSplitTargets_DropLeft() {
         setInSplitScreen(true);
         setRunningTask(mSplitPrimaryAppTask);
-        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
@@ -261,7 +265,7 @@
     public void testDragAppOverSplitApp_expectSplitTargets_DropRight() {
         setInSplitScreen(true);
         setRunningTask(mSplitPrimaryAppTask);
-        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
@@ -274,7 +278,7 @@
     public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropTop() {
         setInSplitScreen(true);
         setRunningTask(mSplitPrimaryAppTask);
-        mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
+        mPolicy.start(mPortraitDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
@@ -287,7 +291,7 @@
     public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropBottom() {
         setInSplitScreen(true);
         setRunningTask(mSplitPrimaryAppTask);
-        mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
+        mPolicy.start(mPortraitDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
@@ -299,7 +303,7 @@
     @Test
     public void testTargetHitRects() {
         setRunningTask(mFullscreenAppTask);
-        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
         ArrayList<Target> targets = mPolicy.getTargets(mInsets);
         for (Target t : targets) {
             assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.top) == t);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
index 99c6107..7b9553c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
@@ -19,6 +19,9 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL;
 
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -109,4 +112,20 @@
 
         assertThat(mSpiedBackgroundPanelOrganizer.mBackgroundSurface).isNull();
     }
+
+    @Test
+    public void testStateNone_onConfigurationChanged() {
+        mSpiedBackgroundPanelOrganizer.onStateChanged(STATE_NONE);
+        mSpiedBackgroundPanelOrganizer.onConfigurationChanged();
+
+        verify(mSpiedBackgroundPanelOrganizer, never()).showBackgroundPanelLayer();
+    }
+
+    @Test
+    public void testStateActivate_onConfigurationChanged() {
+        mSpiedBackgroundPanelOrganizer.onStateChanged(STATE_ACTIVE);
+        mSpiedBackgroundPanelOrganizer.onConfigurationChanged();
+
+        verify(mSpiedBackgroundPanelOrganizer).showBackgroundPanelLayer();
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index ab6f7699..736566e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -33,6 +33,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
@@ -65,9 +66,12 @@
         TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
                 RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
                 MainStage mainStage, SideStage sideStage, DisplayImeController imeController,
-                SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool) {
+                DisplayInsetsController insetsController, SplitLayout splitLayout,
+                Transitions transitions, TransactionPool transactionPool,
+                SplitscreenEventLogger logger) {
             super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
-                    sideStage, imeController, splitLayout, transitions, transactionPool);
+                    sideStage, imeController, insetsController, splitLayout, transitions,
+                    transactionPool, logger);
 
             // Prepare default TaskDisplayArea for testing.
             mDisplayAreaInfo = new DisplayAreaInfo(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index b6da868..d357e77 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -46,6 +46,7 @@
 import android.view.SurfaceSession;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
@@ -58,6 +59,7 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
@@ -79,9 +81,11 @@
     @Mock private SyncTransactionQueue mSyncQueue;
     @Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
     @Mock private DisplayImeController mDisplayImeController;
+    @Mock private DisplayInsetsController mDisplayInsetsController;
     @Mock private TransactionPool mTransactionPool;
     @Mock private Transitions mTransitions;
     @Mock private SurfaceSession mSurfaceSession;
+    @Mock private SplitscreenEventLogger mLogger;
     private SplitLayout mSplitLayout;
     private MainStage mMainStage;
     private SideStage mSideStage;
@@ -106,8 +110,10 @@
                 StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
         mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
-                    mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
-                    mDisplayImeController, mSplitLayout, mTransitions, mTransactionPool);
+                mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
+                mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
+                mTransactionPool,
+                mLogger);
         mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
         doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
                 .when(mTransitions).startTransition(anyInt(), any(), any());
@@ -125,8 +131,8 @@
         TestRemoteTransition testRemote = new TestRemoteTransition();
 
         IBinder transition = mSplitScreenTransitions.startEnterTransition(
-                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(), testRemote,
-                mStageCoordinator);
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
+                new RemoteTransition(testRemote), mStageCoordinator);
         mMainStage.onTaskAppeared(mMainChild, createMockSurface());
         mSideStage.onTaskAppeared(mSideChild, createMockSurface());
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -299,7 +305,7 @@
         TransitionInfo enterInfo = createEnterPairInfo();
         IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
                 TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
-                new TestRemoteTransition(), mStageCoordinator);
+                new RemoteTransition(new TestRemoteTransition()), mStageCoordinator);
         mMainStage.onTaskAppeared(mMainChild, createMockSurface());
         mSideStage.onTaskAppeared(mSideChild, createMockSurface());
         mStageCoordinator.startAnimation(enterTransit, enterInfo,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 06b0868..6cce0ab 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -37,6 +37,7 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.transition.Transitions;
@@ -57,8 +58,10 @@
     @Mock private MainStage mMainStage;
     @Mock private SideStage mSideStage;
     @Mock private DisplayImeController mDisplayImeController;
+    @Mock private DisplayInsetsController mDisplayInsetsController;
     @Mock private Transitions mTransitions;
     @Mock private TransactionPool mTransactionPool;
+    @Mock private SplitscreenEventLogger mLogger;
     private StageCoordinator mStageCoordinator;
 
     @Before
@@ -66,7 +69,8 @@
         MockitoAnnotations.initMocks(this);
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
                 mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
-                mDisplayImeController, null /* splitLayout */, mTransitions, mTransactionPool);
+                mDisplayImeController, mDisplayInsetsController, null /* splitLayout */,
+                mTransitions, mTransactionPool, mLogger);
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index d536adb..2994e71 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 
 import android.app.ActivityManager;
@@ -42,6 +43,7 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.testing.TestableContext;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -84,7 +86,6 @@
 
     static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{
         int mAddWindowForTask = 0;
-        int mViewThemeResId;
 
         TestStartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
                 TransactionPool pool) {
@@ -92,11 +93,10 @@
         }
 
         @Override
-        protected boolean addWindow(int taskId, IBinder appToken,
-                View view, WindowManager wm, WindowManager.LayoutParams params, int suggestType) {
+        protected boolean addWindow(int taskId, IBinder appToken, View view, Display display,
+                WindowManager.LayoutParams params, int suggestType) {
             // listen for addView
             mAddWindowForTask = taskId;
-            mViewThemeResId = view.getContext().getThemeResId();
             // Do not wait for background color
             return false;
         }
@@ -166,12 +166,15 @@
         final int taskId = 1;
         final StartingWindowInfo windowInfo =
                 createWindowInfo(taskId, 0);
+        final int[] theme = new int[1];
+        doAnswer(invocation -> theme[0] = (Integer) invocation.callRealMethod())
+                .when(mStartingSurfaceDrawer).getSplashScreenTheme(eq(0), any());
+
         mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder,
                 STARTING_WINDOW_TYPE_SPLASH_SCREEN);
         waitHandlerIdle(mTestHandler);
-        verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(),
-                eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN));
-        assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0);
+        verify(mStartingSurfaceDrawer).getSplashScreenTheme(eq(0), any());
+        assertNotEquals(theme[0], 0);
     }
 
     @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 21329c7..b0f0d71 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_FLAG_KEYGUARD_GOING_AWAY;
 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;
@@ -49,10 +56,14 @@
 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;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
@@ -66,17 +77,23 @@
 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;
 
 /**
  * Tests for the shell transitions.
+ *
+ * Build/Install/Run:
+ *  atest WMShellUnitTests:ShellTransitionTests
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -98,8 +115,7 @@
 
     @Test
     public void testBasicTransitionFlow() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         IBinder transitToken = new Binder();
@@ -118,8 +134,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();
@@ -202,8 +217,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};
@@ -225,7 +239,8 @@
         };
         IBinder transitToken = new Binder();
         transitions.requestStartTransition(transitToken,
-                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, testRemote));
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */,
+                        new RemoteTransition(testRemote)));
         verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
         TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
                 .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
@@ -296,9 +311,56 @@
     }
 
     @Test
+    public void testTransitionFilterChecksTypeSet() {
+        TransitionFilter filter = new TransitionFilter();
+        filter.mTypeSet = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+
+        final TransitionInfo openOnly = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).build();
+        assertTrue(filter.matches(openOnly));
+
+        final TransitionInfo toFrontOnly = new TransitionInfoBuilder(TRANSIT_TO_FRONT)
+                .addChange(TRANSIT_TO_FRONT).build();
+        assertTrue(filter.matches(toFrontOnly));
+
+        final TransitionInfo closeOnly = new TransitionInfoBuilder(TRANSIT_CLOSE)
+                .addChange(TRANSIT_CLOSE).build();
+        assertFalse(filter.matches(closeOnly));
+    }
+
+    @Test
+    public void testTransitionFilterChecksFlags() {
+        TransitionFilter filter = new TransitionFilter();
+        filter.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+
+        final TransitionInfo withFlag = new TransitionInfoBuilder(TRANSIT_TO_BACK,
+                TRANSIT_FLAG_KEYGUARD_GOING_AWAY)
+                .addChange(TRANSIT_TO_BACK).build();
+        assertTrue(filter.matches(withFlag));
+
+        final TransitionInfo withoutFlag = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).build();
+        assertFalse(filter.matches(withoutFlag));
+    }
+
+    @Test
+    public void testTransitionFilterChecksNotFlags() {
+        TransitionFilter filter = new TransitionFilter();
+        filter.mNotFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+
+        final TransitionInfo withFlag = new TransitionInfoBuilder(TRANSIT_TO_BACK,
+                TRANSIT_FLAG_KEYGUARD_GOING_AWAY)
+                .addChange(TRANSIT_TO_BACK).build();
+        assertFalse(filter.matches(withFlag));
+
+        final TransitionInfo withoutFlag = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).build();
+        assertTrue(filter.matches(withoutFlag));
+    }
+
+    @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};
@@ -323,7 +385,7 @@
                 new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
         filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
 
-        transitions.registerRemote(filter, testRemote);
+        transitions.registerRemote(filter, new RemoteTransition(testRemote));
         mMainExecutor.flushAll();
 
         IBinder transitToken = new Binder();
@@ -343,8 +405,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};
@@ -367,11 +428,12 @@
 
         final int transitType = TRANSIT_FIRST_CUSTOM + 1;
 
-        OneShotRemoteHandler oneShot = new OneShotRemoteHandler(mMainExecutor, testRemote);
+        OneShotRemoteHandler oneShot = new OneShotRemoteHandler(mMainExecutor,
+                new RemoteTransition(testRemote));
         // Verify that it responds to the remote but not other things.
         IBinder transitToken = new Binder();
         assertNotNull(oneShot.handleRequest(transitToken,
-                new TransitionRequestInfo(transitType, null, testRemote)));
+                new TransitionRequestInfo(transitType, null, new RemoteTransition(testRemote))));
         assertNull(oneShot.handleRequest(transitToken,
                 new TransitionRequestInfo(transitType, null, null)));
 
@@ -390,8 +452,7 @@
 
     @Test
     public void testTransitionQueueing() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         IBinder transitToken1 = new Binder();
@@ -431,8 +492,7 @@
 
     @Test
     public void testTransitionMerging() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         mDefaultHandler.setSimulateMerge(true);
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
@@ -468,11 +528,73 @@
         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;
 
         TransitionInfoBuilder(@WindowManager.TransitionType int type) {
-            mInfo = new TransitionInfo(type, 0 /* flags */);
+            this(type, 0 /* flags */);
+        }
+
+        TransitionInfoBuilder(@WindowManager.TransitionType int type,
+                @WindowManager.TransitionFlags int flags) {
+            mInfo = new TransitionInfo(type, flags);
             mInfo.setRootLeash(createMockSurface(true /* valid */), 0, 0);
         }
 
@@ -490,11 +612,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<>();
@@ -566,4 +730,34 @@
         return taskInfo;
     }
 
+    private DisplayController createTestDisplayController() {
+        IWindowManager mockWM = mock(IWindowManager.class);
+        final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
+        try {
+            doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
+        } catch (RemoteException e) {
+            // No remote stuff happening, so this can't be hit
+        }
+        DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
+        out.initialize();
+        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/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 8a10599..2c3567a 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -1,37 +1,37 @@
 // Auto-generated by ./tools/localedata/extract_icu_data.py
 
 const char SCRIPT_CODES[][4] = {
-    /* 0  */ {'A', 'h', 'o', 'm'},
-    /* 1  */ {'A', 'r', 'a', 'b'},
-    /* 2  */ {'A', 'r', 'm', 'i'},
-    /* 3  */ {'A', 'r', 'm', 'n'},
-    /* 4  */ {'A', 'v', 's', 't'},
-    /* 5  */ {'B', 'a', 'm', 'u'},
-    /* 6  */ {'B', 'a', 's', 's'},
-    /* 7  */ {'B', 'e', 'n', 'g'},
-    /* 8  */ {'B', 'r', 'a', 'h'},
-    /* 9  */ {'C', 'a', 'k', 'm'},
-    /* 10 */ {'C', 'a', 'n', 's'},
-    /* 11 */ {'C', 'a', 'r', 'i'},
-    /* 12 */ {'C', 'h', 'a', 'm'},
-    /* 13 */ {'C', 'h', 'e', 'r'},
-    /* 14 */ {'C', 'h', 'r', 's'},
-    /* 15 */ {'C', 'o', 'p', 't'},
-    /* 16 */ {'C', 'p', 'r', 't'},
-    /* 17 */ {'C', 'y', 'r', 'l'},
-    /* 18 */ {'D', 'e', 'v', 'a'},
-    /* 19 */ {'E', 'g', 'y', 'p'},
-    /* 20 */ {'E', 't', 'h', 'i'},
-    /* 21 */ {'G', 'e', 'o', 'r'},
-    /* 22 */ {'G', 'o', 'n', 'g'},
-    /* 23 */ {'G', 'o', 'n', 'm'},
-    /* 24 */ {'G', 'o', 't', 'h'},
-    /* 25 */ {'G', 'r', 'e', 'k'},
-    /* 26 */ {'G', 'u', 'j', 'r'},
-    /* 27 */ {'G', 'u', 'r', 'u'},
-    /* 28 */ {'H', 'a', 'n', 's'},
-    /* 29 */ {'H', 'a', 'n', 't'},
-    /* 30 */ {'H', 'a', 't', 'r'},
+    /* 0  */ {'A', 'g', 'h', 'b'},
+    /* 1  */ {'A', 'h', 'o', 'm'},
+    /* 2  */ {'A', 'r', 'a', 'b'},
+    /* 3  */ {'A', 'r', 'm', 'i'},
+    /* 4  */ {'A', 'r', 'm', 'n'},
+    /* 5  */ {'A', 'v', 's', 't'},
+    /* 6  */ {'B', 'a', 'm', 'u'},
+    /* 7  */ {'B', 'a', 's', 's'},
+    /* 8  */ {'B', 'e', 'n', 'g'},
+    /* 9  */ {'B', 'r', 'a', 'h'},
+    /* 10 */ {'C', 'a', 'k', 'm'},
+    /* 11 */ {'C', 'a', 'n', 's'},
+    /* 12 */ {'C', 'a', 'r', 'i'},
+    /* 13 */ {'C', 'h', 'a', 'm'},
+    /* 14 */ {'C', 'h', 'e', 'r'},
+    /* 15 */ {'C', 'h', 'r', 's'},
+    /* 16 */ {'C', 'o', 'p', 't'},
+    /* 17 */ {'C', 'p', 'r', 't'},
+    /* 18 */ {'C', 'y', 'r', 'l'},
+    /* 19 */ {'D', 'e', 'v', 'a'},
+    /* 20 */ {'E', 'g', 'y', 'p'},
+    /* 21 */ {'E', 't', 'h', 'i'},
+    /* 22 */ {'G', 'e', 'o', 'r'},
+    /* 23 */ {'G', 'o', 'n', 'g'},
+    /* 24 */ {'G', 'o', 'n', 'm'},
+    /* 25 */ {'G', 'o', 't', 'h'},
+    /* 26 */ {'G', 'r', 'e', 'k'},
+    /* 27 */ {'G', 'u', 'j', 'r'},
+    /* 28 */ {'G', 'u', 'r', 'u'},
+    /* 29 */ {'H', 'a', 'n', 's'},
+    /* 30 */ {'H', 'a', 'n', 't'},
     /* 31 */ {'H', 'e', 'b', 'r'},
     /* 32 */ {'H', 'l', 'u', 'w'},
     /* 33 */ {'H', 'm', 'n', 'g'},
@@ -55,52 +55,53 @@
     /* 51 */ {'L', 'y', 'd', 'i'},
     /* 52 */ {'M', 'a', 'n', 'd'},
     /* 53 */ {'M', 'a', 'n', 'i'},
-    /* 54 */ {'M', 'e', 'r', 'c'},
-    /* 55 */ {'M', 'l', 'y', 'm'},
-    /* 56 */ {'M', 'o', 'n', 'g'},
-    /* 57 */ {'M', 'r', 'o', 'o'},
-    /* 58 */ {'M', 'y', 'm', 'r'},
-    /* 59 */ {'N', 'a', 'r', 'b'},
-    /* 60 */ {'N', 'k', 'o', 'o'},
-    /* 61 */ {'N', 's', 'h', 'u'},
-    /* 62 */ {'O', 'g', 'a', 'm'},
-    /* 63 */ {'O', 'l', 'c', 'k'},
-    /* 64 */ {'O', 'r', 'k', 'h'},
-    /* 65 */ {'O', 'r', 'y', 'a'},
-    /* 66 */ {'O', 's', 'g', 'e'},
-    /* 67 */ {'P', 'a', 'u', 'c'},
-    /* 68 */ {'P', 'h', 'l', 'i'},
-    /* 69 */ {'P', 'h', 'n', 'x'},
-    /* 70 */ {'P', 'l', 'r', 'd'},
-    /* 71 */ {'P', 'r', 't', 'i'},
-    /* 72 */ {'R', 'u', 'n', 'r'},
-    /* 73 */ {'S', 'a', 'm', 'r'},
-    /* 74 */ {'S', 'a', 'r', 'b'},
-    /* 75 */ {'S', 'a', 'u', 'r'},
-    /* 76 */ {'S', 'g', 'n', 'w'},
-    /* 77 */ {'S', 'i', 'n', 'h'},
-    /* 78 */ {'S', 'o', 'g', 'd'},
-    /* 79 */ {'S', 'o', 'r', 'a'},
-    /* 80 */ {'S', 'o', 'y', 'o'},
-    /* 81 */ {'S', 'y', 'r', 'c'},
-    /* 82 */ {'T', 'a', 'l', 'e'},
-    /* 83 */ {'T', 'a', 'l', 'u'},
-    /* 84 */ {'T', 'a', 'm', 'l'},
-    /* 85 */ {'T', 'a', 'n', 'g'},
-    /* 86 */ {'T', 'a', 'v', 't'},
-    /* 87 */ {'T', 'e', 'l', 'u'},
-    /* 88 */ {'T', 'f', 'n', 'g'},
-    /* 89 */ {'T', 'h', 'a', 'a'},
-    /* 90 */ {'T', 'h', 'a', 'i'},
-    /* 91 */ {'T', 'i', 'b', 't'},
-    /* 92 */ {'U', 'g', 'a', 'r'},
-    /* 93 */ {'V', 'a', 'i', 'i'},
-    /* 94 */ {'W', 'c', 'h', 'o'},
-    /* 95 */ {'X', 'p', 'e', 'o'},
-    /* 96 */ {'X', 's', 'u', 'x'},
-    /* 97 */ {'Y', 'i', 'i', 'i'},
-    /* 98 */ {'~', '~', '~', 'A'},
-    /* 99 */ {'~', '~', '~', 'B'},
+    /* 54 */ {'M', 'e', 'd', 'f'},
+    /* 55 */ {'M', 'e', 'r', 'c'},
+    /* 56 */ {'M', 'l', 'y', 'm'},
+    /* 57 */ {'M', 'o', 'n', 'g'},
+    /* 58 */ {'M', 'r', 'o', 'o'},
+    /* 59 */ {'M', 'y', 'm', 'r'},
+    /* 60 */ {'N', 'a', 'r', 'b'},
+    /* 61 */ {'N', 'k', 'o', 'o'},
+    /* 62 */ {'N', 's', 'h', 'u'},
+    /* 63 */ {'O', 'g', 'a', 'm'},
+    /* 64 */ {'O', 'l', 'c', 'k'},
+    /* 65 */ {'O', 'r', 'k', 'h'},
+    /* 66 */ {'O', 'r', 'y', 'a'},
+    /* 67 */ {'O', 's', 'g', 'e'},
+    /* 68 */ {'P', 'a', 'u', 'c'},
+    /* 69 */ {'P', 'h', 'l', 'i'},
+    /* 70 */ {'P', 'h', 'n', 'x'},
+    /* 71 */ {'P', 'l', 'r', 'd'},
+    /* 72 */ {'P', 'r', 't', 'i'},
+    /* 73 */ {'R', 'u', 'n', 'r'},
+    /* 74 */ {'S', 'a', 'm', 'r'},
+    /* 75 */ {'S', 'a', 'r', 'b'},
+    /* 76 */ {'S', 'a', 'u', 'r'},
+    /* 77 */ {'S', 'g', 'n', 'w'},
+    /* 78 */ {'S', 'i', 'n', 'h'},
+    /* 79 */ {'S', 'o', 'g', 'd'},
+    /* 80 */ {'S', 'o', 'r', 'a'},
+    /* 81 */ {'S', 'o', 'y', 'o'},
+    /* 82 */ {'S', 'y', 'r', 'c'},
+    /* 83 */ {'T', 'a', 'l', 'e'},
+    /* 84 */ {'T', 'a', 'l', 'u'},
+    /* 85 */ {'T', 'a', 'm', 'l'},
+    /* 86 */ {'T', 'a', 'n', 'g'},
+    /* 87 */ {'T', 'a', 'v', 't'},
+    /* 88 */ {'T', 'e', 'l', 'u'},
+    /* 89 */ {'T', 'f', 'n', 'g'},
+    /* 90 */ {'T', 'h', 'a', 'a'},
+    /* 91 */ {'T', 'h', 'a', 'i'},
+    /* 92 */ {'T', 'i', 'b', 't'},
+    /* 93 */ {'U', 'g', 'a', 'r'},
+    /* 94 */ {'V', 'a', 'i', 'i'},
+    /* 95 */ {'W', 'c', 'h', 'o'},
+    /* 96 */ {'X', 'p', 'e', 'o'},
+    /* 97 */ {'X', 's', 'u', 'x'},
+    /* 98 */ {'Y', 'i', 'i', 'i'},
+    /* 99 */ {'~', '~', '~', 'A'},
+    /* 100 */ {'~', '~', '~', 'B'},
 };
 
 
@@ -109,9 +110,9 @@
     {0xA0000000u, 46u}, // aai -> Latn
     {0xA8000000u, 46u}, // aak -> Latn
     {0xD0000000u, 46u}, // aau -> Latn
-    {0x61620000u, 17u}, // ab -> Cyrl
+    {0x61620000u, 18u}, // ab -> Cyrl
     {0xA0200000u, 46u}, // abi -> Latn
-    {0xC0200000u, 17u}, // abq -> Cyrl
+    {0xC0200000u, 18u}, // abq -> Cyrl
     {0xC4200000u, 46u}, // abr -> Latn
     {0xCC200000u, 46u}, // abt -> Latn
     {0xE0200000u, 46u}, // aby -> Latn
@@ -121,11 +122,11 @@
     {0x80600000u, 46u}, // ada -> Latn
     {0x90600000u, 46u}, // ade -> Latn
     {0xA4600000u, 46u}, // adj -> Latn
-    {0xBC600000u, 91u}, // adp -> Tibt
-    {0xE0600000u, 17u}, // ady -> Cyrl
+    {0xBC600000u, 92u}, // adp -> Tibt
+    {0xE0600000u, 18u}, // ady -> Cyrl
     {0xE4600000u, 46u}, // adz -> Latn
-    {0x61650000u,  4u}, // ae -> Avst
-    {0x84800000u,  1u}, // aeb -> Arab
+    {0x61650000u,  5u}, // ae -> Avst
+    {0x84800000u,  2u}, // aeb -> Arab
     {0xE0800000u, 46u}, // aey -> Latn
     {0x61660000u, 46u}, // af -> Latn
     {0x88C00000u, 46u}, // agc -> Latn
@@ -136,15 +137,15 @@
     {0xC0C00000u, 46u}, // agq -> Latn
     {0x80E00000u, 46u}, // aha -> Latn
     {0xACE00000u, 46u}, // ahl -> Latn
-    {0xB8E00000u,  0u}, // aho -> Ahom
+    {0xB8E00000u,  1u}, // aho -> Ahom
     {0x99200000u, 46u}, // ajg -> Latn
     {0x616B0000u, 46u}, // ak -> Latn
-    {0xA9400000u, 96u}, // akk -> Xsux
+    {0xA9400000u, 97u}, // akk -> Xsux
     {0x81600000u, 46u}, // ala -> Latn
     {0xA1600000u, 46u}, // ali -> Latn
     {0xB5600000u, 46u}, // aln -> Latn
-    {0xCD600000u, 17u}, // alt -> Cyrl
-    {0x616D0000u, 20u}, // am -> Ethi
+    {0xCD600000u, 18u}, // alt -> Cyrl
+    {0x616D0000u, 21u}, // am -> Ethi
     {0xB1800000u, 46u}, // amm -> Latn
     {0xB5800000u, 46u}, // amn -> Latn
     {0xB9800000u, 46u}, // amo -> Latn
@@ -157,25 +158,25 @@
     {0xA5C00000u, 46u}, // aoj -> Latn
     {0xB1C00000u, 46u}, // aom -> Latn
     {0xE5C00000u, 46u}, // aoz -> Latn
-    {0x89E00000u,  1u}, // apc -> Arab
-    {0x8DE00000u,  1u}, // apd -> Arab
+    {0x89E00000u,  2u}, // apc -> Arab
+    {0x8DE00000u,  2u}, // apd -> Arab
     {0x91E00000u, 46u}, // ape -> Latn
     {0xC5E00000u, 46u}, // apr -> Latn
     {0xC9E00000u, 46u}, // aps -> Latn
     {0xE5E00000u, 46u}, // apz -> Latn
-    {0x61720000u,  1u}, // ar -> Arab
-    {0x61725842u, 99u}, // ar-XB -> ~~~B
-    {0x8A200000u,  2u}, // arc -> Armi
+    {0x61720000u,  2u}, // ar -> Arab
+    {0x61725842u, 100u}, // ar-XB -> ~~~B
+    {0x8A200000u,  3u}, // arc -> Armi
     {0x9E200000u, 46u}, // arh -> Latn
     {0xB6200000u, 46u}, // arn -> Latn
     {0xBA200000u, 46u}, // aro -> Latn
-    {0xC2200000u,  1u}, // arq -> Arab
-    {0xCA200000u,  1u}, // ars -> Arab
-    {0xE2200000u,  1u}, // ary -> Arab
-    {0xE6200000u,  1u}, // arz -> Arab
-    {0x61730000u,  7u}, // as -> Beng
+    {0xC2200000u,  2u}, // arq -> Arab
+    {0xCA200000u,  2u}, // ars -> Arab
+    {0xE2200000u,  2u}, // ary -> Arab
+    {0xE6200000u,  2u}, // arz -> Arab
+    {0x61730000u,  8u}, // as -> Beng
     {0x82400000u, 46u}, // asa -> Latn
-    {0x92400000u, 76u}, // ase -> Sgnw
+    {0x92400000u, 77u}, // ase -> Sgnw
     {0x9A400000u, 46u}, // asg -> Latn
     {0xBA400000u, 46u}, // aso -> Latn
     {0xCE400000u, 46u}, // ast -> Latn
@@ -183,29 +184,29 @@
     {0x9A600000u, 46u}, // atg -> Latn
     {0xA6600000u, 46u}, // atj -> Latn
     {0xE2800000u, 46u}, // auy -> Latn
-    {0x61760000u, 17u}, // av -> Cyrl
-    {0xAEA00000u,  1u}, // avl -> Arab
+    {0x61760000u, 18u}, // av -> Cyrl
+    {0xAEA00000u,  2u}, // avl -> Arab
     {0xB6A00000u, 46u}, // avn -> Latn
     {0xCEA00000u, 46u}, // avt -> Latn
     {0xD2A00000u, 46u}, // avu -> Latn
-    {0x82C00000u, 18u}, // awa -> Deva
+    {0x82C00000u, 19u}, // awa -> Deva
     {0x86C00000u, 46u}, // awb -> Latn
     {0xBAC00000u, 46u}, // awo -> Latn
     {0xDEC00000u, 46u}, // awx -> Latn
     {0x61790000u, 46u}, // ay -> Latn
     {0x87000000u, 46u}, // ayb -> Latn
     {0x617A0000u, 46u}, // az -> Latn
-    {0x617A4951u,  1u}, // az-IQ -> Arab
-    {0x617A4952u,  1u}, // az-IR -> Arab
-    {0x617A5255u, 17u}, // az-RU -> Cyrl
-    {0x62610000u, 17u}, // ba -> Cyrl
-    {0xAC010000u,  1u}, // bal -> Arab
+    {0x617A4951u,  2u}, // az-IQ -> Arab
+    {0x617A4952u,  2u}, // az-IR -> Arab
+    {0x617A5255u, 18u}, // az-RU -> Cyrl
+    {0x62610000u, 18u}, // ba -> Cyrl
+    {0xAC010000u,  2u}, // bal -> Arab
     {0xB4010000u, 46u}, // ban -> Latn
-    {0xBC010000u, 18u}, // bap -> Deva
+    {0xBC010000u, 19u}, // bap -> Deva
     {0xC4010000u, 46u}, // bar -> Latn
     {0xC8010000u, 46u}, // bas -> Latn
     {0xD4010000u, 46u}, // bav -> Latn
-    {0xDC010000u,  5u}, // bax -> Bamu
+    {0xDC010000u,  6u}, // bax -> Bamu
     {0x80210000u, 46u}, // bba -> Latn
     {0x84210000u, 46u}, // bbb -> Latn
     {0x88210000u, 46u}, // bbc -> Latn
@@ -219,31 +220,31 @@
     {0xB0410000u, 46u}, // bcm -> Latn
     {0xB4410000u, 46u}, // bcn -> Latn
     {0xB8410000u, 46u}, // bco -> Latn
-    {0xC0410000u, 20u}, // bcq -> Ethi
+    {0xC0410000u, 21u}, // bcq -> Ethi
     {0xD0410000u, 46u}, // bcu -> Latn
     {0x8C610000u, 46u}, // bdd -> Latn
-    {0x62650000u, 17u}, // be -> Cyrl
+    {0x62650000u, 18u}, // be -> Cyrl
     {0x94810000u, 46u}, // bef -> Latn
     {0x9C810000u, 46u}, // beh -> Latn
-    {0xA4810000u,  1u}, // bej -> Arab
+    {0xA4810000u,  2u}, // bej -> Arab
     {0xB0810000u, 46u}, // bem -> Latn
     {0xCC810000u, 46u}, // bet -> Latn
     {0xD8810000u, 46u}, // bew -> Latn
     {0xDC810000u, 46u}, // bex -> Latn
     {0xE4810000u, 46u}, // bez -> Latn
     {0x8CA10000u, 46u}, // bfd -> Latn
-    {0xC0A10000u, 84u}, // bfq -> Taml
-    {0xCCA10000u,  1u}, // bft -> Arab
-    {0xE0A10000u, 18u}, // bfy -> Deva
-    {0x62670000u, 17u}, // bg -> Cyrl
-    {0x88C10000u, 18u}, // bgc -> Deva
-    {0xB4C10000u,  1u}, // bgn -> Arab
-    {0xDCC10000u, 25u}, // bgx -> Grek
-    {0x84E10000u, 18u}, // bhb -> Deva
+    {0xC0A10000u, 85u}, // bfq -> Taml
+    {0xCCA10000u,  2u}, // bft -> Arab
+    {0xE0A10000u, 19u}, // bfy -> Deva
+    {0x62670000u, 18u}, // bg -> Cyrl
+    {0x88C10000u, 19u}, // bgc -> Deva
+    {0xB4C10000u,  2u}, // bgn -> Arab
+    {0xDCC10000u, 26u}, // bgx -> Grek
+    {0x84E10000u, 19u}, // bhb -> Deva
     {0x98E10000u, 46u}, // bhg -> Latn
-    {0xA0E10000u, 18u}, // bhi -> Deva
+    {0xA0E10000u, 19u}, // bhi -> Deva
     {0xACE10000u, 46u}, // bhl -> Latn
-    {0xB8E10000u, 18u}, // bho -> Deva
+    {0xB8E10000u, 19u}, // bho -> Deva
     {0xE0E10000u, 46u}, // bhy -> Latn
     {0x62690000u, 46u}, // bi -> Latn
     {0x85010000u, 46u}, // bib -> Latn
@@ -254,8 +255,8 @@
     {0xB9010000u, 46u}, // bio -> Latn
     {0xC1010000u, 46u}, // biq -> Latn
     {0x9D210000u, 46u}, // bjh -> Latn
-    {0xA1210000u, 20u}, // bji -> Ethi
-    {0xA5210000u, 18u}, // bjj -> Deva
+    {0xA1210000u, 21u}, // bji -> Ethi
+    {0xA5210000u, 19u}, // bjj -> Deva
     {0xB5210000u, 46u}, // bjn -> Latn
     {0xB9210000u, 46u}, // bjo -> Latn
     {0xC5210000u, 46u}, // bjr -> Latn
@@ -266,39 +267,39 @@
     {0xC1410000u, 46u}, // bkq -> Latn
     {0xD1410000u, 46u}, // bku -> Latn
     {0xD5410000u, 46u}, // bkv -> Latn
-    {0xCD610000u, 86u}, // blt -> Tavt
+    {0xCD610000u, 87u}, // blt -> Tavt
     {0x626D0000u, 46u}, // bm -> Latn
     {0x9D810000u, 46u}, // bmh -> Latn
     {0xA9810000u, 46u}, // bmk -> Latn
     {0xC1810000u, 46u}, // bmq -> Latn
     {0xD1810000u, 46u}, // bmu -> Latn
-    {0x626E0000u,  7u}, // bn -> Beng
+    {0x626E0000u,  8u}, // bn -> Beng
     {0x99A10000u, 46u}, // bng -> Latn
     {0xB1A10000u, 46u}, // bnm -> Latn
     {0xBDA10000u, 46u}, // bnp -> Latn
-    {0x626F0000u, 91u}, // bo -> Tibt
+    {0x626F0000u, 92u}, // bo -> Tibt
     {0xA5C10000u, 46u}, // boj -> Latn
     {0xB1C10000u, 46u}, // bom -> Latn
     {0xB5C10000u, 46u}, // bon -> Latn
-    {0xE1E10000u,  7u}, // bpy -> Beng
+    {0xE1E10000u,  8u}, // bpy -> Beng
     {0x8A010000u, 46u}, // bqc -> Latn
-    {0xA2010000u,  1u}, // bqi -> Arab
+    {0xA2010000u,  2u}, // bqi -> Arab
     {0xBE010000u, 46u}, // bqp -> Latn
     {0xD6010000u, 46u}, // bqv -> Latn
     {0x62720000u, 46u}, // br -> Latn
-    {0x82210000u, 18u}, // bra -> Deva
-    {0x9E210000u,  1u}, // brh -> Arab
-    {0xDE210000u, 18u}, // brx -> Deva
+    {0x82210000u, 19u}, // bra -> Deva
+    {0x9E210000u,  2u}, // brh -> Arab
+    {0xDE210000u, 19u}, // brx -> Deva
     {0xE6210000u, 46u}, // brz -> Latn
     {0x62730000u, 46u}, // bs -> Latn
     {0xA6410000u, 46u}, // bsj -> Latn
-    {0xC2410000u,  6u}, // bsq -> Bass
+    {0xC2410000u,  7u}, // bsq -> Bass
     {0xCA410000u, 46u}, // bss -> Latn
-    {0xCE410000u, 20u}, // bst -> Ethi
+    {0xCE410000u, 21u}, // bst -> Ethi
     {0xBA610000u, 46u}, // bto -> Latn
     {0xCE610000u, 46u}, // btt -> Latn
-    {0xD6610000u, 18u}, // btv -> Deva
-    {0x82810000u, 17u}, // bua -> Cyrl
+    {0xD6610000u, 19u}, // btv -> Deva
+    {0x82810000u, 18u}, // bua -> Cyrl
     {0x8A810000u, 46u}, // buc -> Latn
     {0x8E810000u, 46u}, // bud -> Latn
     {0x9A810000u, 46u}, // bug -> Latn
@@ -312,7 +313,7 @@
     {0xC6C10000u, 46u}, // bwr -> Latn
     {0x9EE10000u, 46u}, // bxh -> Latn
     {0x93010000u, 46u}, // bye -> Latn
-    {0xB7010000u, 20u}, // byn -> Ethi
+    {0xB7010000u, 21u}, // byn -> Ethi
     {0xC7010000u, 46u}, // byr -> Latn
     {0xCB010000u, 46u}, // bys -> Latn
     {0xD7010000u, 46u}, // byv -> Latn
@@ -327,44 +328,44 @@
     {0xB4020000u, 46u}, // can -> Latn
     {0xA4220000u, 46u}, // cbj -> Latn
     {0x9C420000u, 46u}, // cch -> Latn
-    {0xBC420000u,  9u}, // ccp -> Cakm
-    {0x63650000u, 17u}, // ce -> Cyrl
+    {0xBC420000u, 10u}, // ccp -> Cakm
+    {0x63650000u, 18u}, // ce -> Cyrl
     {0x84820000u, 46u}, // ceb -> Latn
     {0x80A20000u, 46u}, // cfa -> Latn
     {0x98C20000u, 46u}, // cgg -> Latn
     {0x63680000u, 46u}, // ch -> Latn
     {0xA8E20000u, 46u}, // chk -> Latn
-    {0xB0E20000u, 17u}, // chm -> Cyrl
+    {0xB0E20000u, 18u}, // chm -> Cyrl
     {0xB8E20000u, 46u}, // cho -> Latn
     {0xBCE20000u, 46u}, // chp -> Latn
-    {0xC4E20000u, 13u}, // chr -> Cher
+    {0xC4E20000u, 14u}, // chr -> Cher
     {0x89020000u, 46u}, // cic -> Latn
-    {0x81220000u,  1u}, // cja -> Arab
-    {0xB1220000u, 12u}, // cjm -> Cham
+    {0x81220000u,  2u}, // cja -> Arab
+    {0xB1220000u, 13u}, // cjm -> Cham
     {0xD5220000u, 46u}, // cjv -> Latn
-    {0x85420000u,  1u}, // ckb -> Arab
+    {0x85420000u,  2u}, // ckb -> Arab
     {0xAD420000u, 46u}, // ckl -> Latn
     {0xB9420000u, 46u}, // cko -> Latn
     {0xE1420000u, 46u}, // cky -> Latn
     {0x81620000u, 46u}, // cla -> Latn
     {0x91820000u, 46u}, // cme -> Latn
-    {0x99820000u, 80u}, // cmg -> Soyo
+    {0x99820000u, 81u}, // cmg -> Soyo
     {0x636F0000u, 46u}, // co -> Latn
-    {0xBDC20000u, 15u}, // cop -> Copt
+    {0xBDC20000u, 16u}, // cop -> Copt
     {0xC9E20000u, 46u}, // cps -> Latn
-    {0x63720000u, 10u}, // cr -> Cans
-    {0x9E220000u, 17u}, // crh -> Cyrl
-    {0xA6220000u, 10u}, // crj -> Cans
-    {0xAA220000u, 10u}, // crk -> Cans
-    {0xAE220000u, 10u}, // crl -> Cans
-    {0xB2220000u, 10u}, // crm -> Cans
+    {0x63720000u, 11u}, // cr -> Cans
+    {0x9E220000u, 18u}, // crh -> Cyrl
+    {0xA6220000u, 11u}, // crj -> Cans
+    {0xAA220000u, 11u}, // crk -> Cans
+    {0xAE220000u, 11u}, // crl -> Cans
+    {0xB2220000u, 11u}, // crm -> Cans
     {0xCA220000u, 46u}, // crs -> Latn
     {0x63730000u, 46u}, // cs -> Latn
     {0x86420000u, 46u}, // csb -> Latn
-    {0xDA420000u, 10u}, // csw -> Cans
-    {0x8E620000u, 67u}, // ctd -> Pauc
-    {0x63750000u, 17u}, // cu -> Cyrl
-    {0x63760000u, 17u}, // cv -> Cyrl
+    {0xDA420000u, 11u}, // csw -> Cans
+    {0x8E620000u, 68u}, // ctd -> Pauc
+    {0x63750000u, 18u}, // cu -> Cyrl
+    {0x63760000u, 18u}, // cv -> Cyrl
     {0x63790000u, 46u}, // cy -> Latn
     {0x64610000u, 46u}, // da -> Latn
     {0x8C030000u, 46u}, // dad -> Latn
@@ -372,11 +373,11 @@
     {0x98030000u, 46u}, // dag -> Latn
     {0x9C030000u, 46u}, // dah -> Latn
     {0xA8030000u, 46u}, // dak -> Latn
-    {0xC4030000u, 17u}, // dar -> Cyrl
+    {0xC4030000u, 18u}, // dar -> Cyrl
     {0xD4030000u, 46u}, // dav -> Latn
     {0x8C230000u, 46u}, // dbd -> Latn
     {0xC0230000u, 46u}, // dbq -> Latn
-    {0x88430000u,  1u}, // dcc -> Arab
+    {0x88430000u,  2u}, // dcc -> Arab
     {0xB4630000u, 46u}, // ddn -> Latn
     {0x64650000u, 46u}, // de -> Latn
     {0x8C830000u, 46u}, // ded -> Latn
@@ -384,53 +385,54 @@
     {0x80C30000u, 46u}, // dga -> Latn
     {0x9CC30000u, 46u}, // dgh -> Latn
     {0xA0C30000u, 46u}, // dgi -> Latn
-    {0xACC30000u,  1u}, // dgl -> Arab
+    {0xACC30000u,  2u}, // dgl -> Arab
     {0xC4C30000u, 46u}, // dgr -> Latn
     {0xE4C30000u, 46u}, // dgz -> Latn
     {0x81030000u, 46u}, // dia -> Latn
     {0x91230000u, 46u}, // dje -> Latn
+    {0x95830000u, 54u}, // dmf -> Medf
     {0xA5A30000u, 46u}, // dnj -> Latn
     {0x85C30000u, 46u}, // dob -> Latn
-    {0xA1C30000u, 18u}, // doi -> Deva
+    {0xA1C30000u, 19u}, // doi -> Deva
     {0xBDC30000u, 46u}, // dop -> Latn
     {0xD9C30000u, 46u}, // dow -> Latn
-    {0x9E230000u, 56u}, // drh -> Mong
+    {0x9E230000u, 57u}, // drh -> Mong
     {0xA2230000u, 46u}, // dri -> Latn
-    {0xCA230000u, 20u}, // drs -> Ethi
+    {0xCA230000u, 21u}, // drs -> Ethi
     {0x86430000u, 46u}, // dsb -> Latn
     {0xB2630000u, 46u}, // dtm -> Latn
     {0xBE630000u, 46u}, // dtp -> Latn
     {0xCA630000u, 46u}, // dts -> Latn
-    {0xE2630000u, 18u}, // dty -> Deva
+    {0xE2630000u, 19u}, // dty -> Deva
     {0x82830000u, 46u}, // dua -> Latn
     {0x8A830000u, 46u}, // duc -> Latn
     {0x8E830000u, 46u}, // dud -> Latn
     {0x9A830000u, 46u}, // dug -> Latn
-    {0x64760000u, 89u}, // dv -> Thaa
+    {0x64760000u, 90u}, // dv -> Thaa
     {0x82A30000u, 46u}, // dva -> Latn
     {0xDAC30000u, 46u}, // dww -> Latn
     {0xBB030000u, 46u}, // dyo -> Latn
     {0xD3030000u, 46u}, // dyu -> Latn
-    {0x647A0000u, 91u}, // dz -> Tibt
+    {0x647A0000u, 92u}, // dz -> Tibt
     {0x9B230000u, 46u}, // dzg -> Latn
     {0xD0240000u, 46u}, // ebu -> Latn
     {0x65650000u, 46u}, // ee -> Latn
     {0xA0A40000u, 46u}, // efi -> Latn
     {0xACC40000u, 46u}, // egl -> Latn
-    {0xE0C40000u, 19u}, // egy -> Egyp
+    {0xE0C40000u, 20u}, // egy -> Egyp
     {0x81440000u, 46u}, // eka -> Latn
     {0xE1440000u, 37u}, // eky -> Kali
-    {0x656C0000u, 25u}, // el -> Grek
+    {0x656C0000u, 26u}, // el -> Grek
     {0x81840000u, 46u}, // ema -> Latn
     {0xA1840000u, 46u}, // emi -> Latn
     {0x656E0000u, 46u}, // en -> Latn
-    {0x656E5841u, 98u}, // en-XA -> ~~~A
+    {0x656E5841u, 99u}, // en-XA -> ~~~A
     {0xB5A40000u, 46u}, // enn -> Latn
     {0xC1A40000u, 46u}, // enq -> Latn
     {0x656F0000u, 46u}, // eo -> Latn
     {0xA2240000u, 46u}, // eri -> Latn
     {0x65730000u, 46u}, // es -> Latn
-    {0x9A440000u, 23u}, // esg -> Gonm
+    {0x9A440000u, 24u}, // esg -> Gonm
     {0xD2440000u, 46u}, // esu -> Latn
     {0x65740000u, 46u}, // et -> Latn
     {0xC6640000u, 46u}, // etr -> Latn
@@ -441,7 +443,7 @@
     {0xBAC40000u, 46u}, // ewo -> Latn
     {0xCEE40000u, 46u}, // ext -> Latn
     {0x83240000u, 46u}, // eza -> Latn
-    {0x66610000u,  1u}, // fa -> Arab
+    {0x66610000u,  2u}, // fa -> Arab
     {0x80050000u, 46u}, // faa -> Latn
     {0x84050000u, 46u}, // fab -> Latn
     {0x98050000u, 46u}, // fag -> Latn
@@ -451,7 +453,7 @@
     {0xA0A50000u, 46u}, // ffi -> Latn
     {0xB0A50000u, 46u}, // ffm -> Latn
     {0x66690000u, 46u}, // fi -> Latn
-    {0x81050000u,  1u}, // fia -> Arab
+    {0x81050000u,  2u}, // fia -> Arab
     {0xAD050000u, 46u}, // fil -> Latn
     {0xCD050000u, 46u}, // fit -> Latn
     {0x666A0000u, 46u}, // fj -> Latn
@@ -468,7 +470,7 @@
     {0xBE250000u, 46u}, // frp -> Latn
     {0xC6250000u, 46u}, // frr -> Latn
     {0xCA250000u, 46u}, // frs -> Latn
-    {0x86850000u,  1u}, // fub -> Arab
+    {0x86850000u,  2u}, // fub -> Arab
     {0x8E850000u, 46u}, // fud -> Latn
     {0x92850000u, 46u}, // fue -> Latn
     {0x96850000u, 46u}, // fuf -> Latn
@@ -486,14 +488,14 @@
     {0x9C060000u, 46u}, // gah -> Latn
     {0xA4060000u, 46u}, // gaj -> Latn
     {0xB0060000u, 46u}, // gam -> Latn
-    {0xB4060000u, 28u}, // gan -> Hans
+    {0xB4060000u, 29u}, // gan -> Hans
     {0xD8060000u, 46u}, // gaw -> Latn
     {0xE0060000u, 46u}, // gay -> Latn
     {0x80260000u, 46u}, // gba -> Latn
     {0x94260000u, 46u}, // gbf -> Latn
-    {0xB0260000u, 18u}, // gbm -> Deva
+    {0xB0260000u, 19u}, // gbm -> Deva
     {0xE0260000u, 46u}, // gby -> Latn
-    {0xE4260000u,  1u}, // gbz -> Arab
+    {0xE4260000u,  2u}, // gbz -> Arab
     {0xC4460000u, 46u}, // gcr -> Latn
     {0x67640000u, 46u}, // gd -> Latn
     {0x90660000u, 46u}, // gde -> Latn
@@ -502,38 +504,38 @@
     {0x84860000u, 46u}, // geb -> Latn
     {0xA4860000u, 46u}, // gej -> Latn
     {0xAC860000u, 46u}, // gel -> Latn
-    {0xE4860000u, 20u}, // gez -> Ethi
+    {0xE4860000u, 21u}, // gez -> Ethi
     {0xA8A60000u, 46u}, // gfk -> Latn
-    {0xB4C60000u, 18u}, // ggn -> Deva
+    {0xB4C60000u, 19u}, // ggn -> Deva
     {0xC8E60000u, 46u}, // ghs -> Latn
     {0xAD060000u, 46u}, // gil -> Latn
     {0xB1060000u, 46u}, // gim -> Latn
-    {0xA9260000u,  1u}, // gjk -> Arab
+    {0xA9260000u,  2u}, // gjk -> Arab
     {0xB5260000u, 46u}, // gjn -> Latn
-    {0xD1260000u,  1u}, // gju -> Arab
+    {0xD1260000u,  2u}, // gju -> Arab
     {0xB5460000u, 46u}, // gkn -> Latn
     {0xBD460000u, 46u}, // gkp -> Latn
     {0x676C0000u, 46u}, // gl -> Latn
-    {0xA9660000u,  1u}, // glk -> Arab
+    {0xA9660000u,  2u}, // glk -> Arab
     {0xB1860000u, 46u}, // gmm -> Latn
-    {0xD5860000u, 20u}, // gmv -> Ethi
+    {0xD5860000u, 21u}, // gmv -> Ethi
     {0x676E0000u, 46u}, // gn -> Latn
     {0x8DA60000u, 46u}, // gnd -> Latn
     {0x99A60000u, 46u}, // gng -> Latn
     {0x8DC60000u, 46u}, // god -> Latn
-    {0x95C60000u, 20u}, // gof -> Ethi
+    {0x95C60000u, 21u}, // gof -> Ethi
     {0xA1C60000u, 46u}, // goi -> Latn
-    {0xB1C60000u, 18u}, // gom -> Deva
-    {0xB5C60000u, 87u}, // gon -> Telu
+    {0xB1C60000u, 19u}, // gom -> Deva
+    {0xB5C60000u, 88u}, // gon -> Telu
     {0xC5C60000u, 46u}, // gor -> Latn
     {0xC9C60000u, 46u}, // gos -> Latn
-    {0xCDC60000u, 24u}, // got -> Goth
+    {0xCDC60000u, 25u}, // got -> Goth
     {0x86260000u, 46u}, // grb -> Latn
-    {0x8A260000u, 16u}, // grc -> Cprt
-    {0xCE260000u,  7u}, // grt -> Beng
+    {0x8A260000u, 17u}, // grc -> Cprt
+    {0xCE260000u,  8u}, // grt -> Beng
     {0xDA260000u, 46u}, // grw -> Latn
     {0xDA460000u, 46u}, // gsw -> Latn
-    {0x67750000u, 26u}, // gu -> Gujr
+    {0x67750000u, 27u}, // gu -> Gujr
     {0x86860000u, 46u}, // gub -> Latn
     {0x8A860000u, 46u}, // guc -> Latn
     {0x8E860000u, 46u}, // gud -> Latn
@@ -543,25 +545,25 @@
     {0xE6860000u, 46u}, // guz -> Latn
     {0x67760000u, 46u}, // gv -> Latn
     {0x96A60000u, 46u}, // gvf -> Latn
-    {0xC6A60000u, 18u}, // gvr -> Deva
+    {0xC6A60000u, 19u}, // gvr -> Deva
     {0xCAA60000u, 46u}, // gvs -> Latn
-    {0x8AC60000u,  1u}, // gwc -> Arab
+    {0x8AC60000u,  2u}, // gwc -> Arab
     {0xA2C60000u, 46u}, // gwi -> Latn
-    {0xCEC60000u,  1u}, // gwt -> Arab
+    {0xCEC60000u,  2u}, // gwt -> Arab
     {0xA3060000u, 46u}, // gyi -> Latn
     {0x68610000u, 46u}, // ha -> Latn
-    {0x6861434Du,  1u}, // ha-CM -> Arab
-    {0x68615344u,  1u}, // ha-SD -> Arab
+    {0x6861434Du,  2u}, // ha-CM -> Arab
+    {0x68615344u,  2u}, // ha-SD -> Arab
     {0x98070000u, 46u}, // hag -> Latn
-    {0xA8070000u, 28u}, // hak -> Hans
+    {0xA8070000u, 29u}, // hak -> Hans
     {0xB0070000u, 46u}, // ham -> Latn
     {0xD8070000u, 46u}, // haw -> Latn
-    {0xE4070000u,  1u}, // haz -> Arab
+    {0xE4070000u,  2u}, // haz -> Arab
     {0x84270000u, 46u}, // hbb -> Latn
-    {0xE0670000u, 20u}, // hdy -> Ethi
+    {0xE0670000u, 21u}, // hdy -> Ethi
     {0x68650000u, 31u}, // he -> Hebr
     {0xE0E70000u, 46u}, // hhy -> Latn
-    {0x68690000u, 18u}, // hi -> Deva
+    {0x68690000u, 19u}, // hi -> Deva
     {0x81070000u, 46u}, // hia -> Latn
     {0x95070000u, 46u}, // hif -> Latn
     {0x99070000u, 46u}, // hig -> Latn
@@ -569,24 +571,24 @@
     {0xAD070000u, 46u}, // hil -> Latn
     {0x81670000u, 46u}, // hla -> Latn
     {0xD1670000u, 32u}, // hlu -> Hluw
-    {0x8D870000u, 70u}, // hmd -> Plrd
+    {0x8D870000u, 71u}, // hmd -> Plrd
     {0xCD870000u, 46u}, // hmt -> Latn
-    {0x8DA70000u,  1u}, // hnd -> Arab
-    {0x91A70000u, 18u}, // hne -> Deva
+    {0x8DA70000u,  2u}, // hnd -> Arab
+    {0x91A70000u, 19u}, // hne -> Deva
     {0xA5A70000u, 33u}, // hnj -> Hmng
     {0xB5A70000u, 46u}, // hnn -> Latn
-    {0xB9A70000u,  1u}, // hno -> Arab
+    {0xB9A70000u,  2u}, // hno -> Arab
     {0x686F0000u, 46u}, // ho -> Latn
-    {0x89C70000u, 18u}, // hoc -> Deva
-    {0xA5C70000u, 18u}, // hoj -> Deva
+    {0x89C70000u, 19u}, // hoc -> Deva
+    {0xA5C70000u, 19u}, // hoj -> Deva
     {0xCDC70000u, 46u}, // hot -> Latn
     {0x68720000u, 46u}, // hr -> Latn
     {0x86470000u, 46u}, // hsb -> Latn
-    {0xB6470000u, 28u}, // hsn -> Hans
+    {0xB6470000u, 29u}, // hsn -> Hans
     {0x68740000u, 46u}, // ht -> Latn
     {0x68750000u, 46u}, // hu -> Latn
     {0xA2870000u, 46u}, // hui -> Latn
-    {0x68790000u,  3u}, // hy -> Armn
+    {0x68790000u,  4u}, // hy -> Armn
     {0x687A0000u, 46u}, // hz -> Latn
     {0x69610000u, 46u}, // ia -> Latn
     {0xB4080000u, 46u}, // ian -> Latn
@@ -604,7 +606,7 @@
     {0x69670000u, 46u}, // ig -> Latn
     {0x84C80000u, 46u}, // igb -> Latn
     {0x90C80000u, 46u}, // ige -> Latn
-    {0x69690000u, 97u}, // ii -> Yiii
+    {0x69690000u, 98u}, // ii -> Yiii
     {0xA5280000u, 46u}, // ijj -> Latn
     {0x696B0000u, 46u}, // ik -> Latn
     {0xA9480000u, 46u}, // ikk -> Latn
@@ -614,13 +616,13 @@
     {0xB9680000u, 46u}, // ilo -> Latn
     {0xB9880000u, 46u}, // imo -> Latn
     {0x696E0000u, 46u}, // in -> Latn
-    {0x9DA80000u, 17u}, // inh -> Cyrl
+    {0x9DA80000u, 18u}, // inh -> Cyrl
     {0x696F0000u, 46u}, // io -> Latn
     {0xD1C80000u, 46u}, // iou -> Latn
     {0xA2280000u, 46u}, // iri -> Latn
     {0x69730000u, 46u}, // is -> Latn
     {0x69740000u, 46u}, // it -> Latn
-    {0x69750000u, 10u}, // iu -> Cans
+    {0x69750000u, 11u}, // iu -> Cans
     {0x69770000u, 31u}, // iw -> Hebr
     {0xB2C80000u, 46u}, // iwm -> Latn
     {0xCAC80000u, 46u}, // iws -> Latn
@@ -638,13 +640,13 @@
     {0x6A690000u, 31u}, // ji -> Hebr
     {0x85090000u, 46u}, // jib -> Latn
     {0x89890000u, 46u}, // jmc -> Latn
-    {0xAD890000u, 18u}, // jml -> Deva
+    {0xAD890000u, 19u}, // jml -> Deva
     {0x82290000u, 46u}, // jra -> Latn
     {0xCE890000u, 46u}, // jut -> Latn
     {0x6A760000u, 46u}, // jv -> Latn
     {0x6A770000u, 46u}, // jw -> Latn
-    {0x6B610000u, 21u}, // ka -> Geor
-    {0x800A0000u, 17u}, // kaa -> Cyrl
+    {0x6B610000u, 22u}, // ka -> Geor
+    {0x800A0000u, 18u}, // kaa -> Cyrl
     {0x840A0000u, 46u}, // kab -> Latn
     {0x880A0000u, 46u}, // kac -> Latn
     {0x8C0A0000u, 46u}, // kad -> Latn
@@ -652,37 +654,37 @@
     {0xA40A0000u, 46u}, // kaj -> Latn
     {0xB00A0000u, 46u}, // kam -> Latn
     {0xB80A0000u, 46u}, // kao -> Latn
-    {0x8C2A0000u, 17u}, // kbd -> Cyrl
+    {0x8C2A0000u, 18u}, // kbd -> Cyrl
     {0xB02A0000u, 46u}, // kbm -> Latn
     {0xBC2A0000u, 46u}, // kbp -> Latn
     {0xC02A0000u, 46u}, // kbq -> Latn
     {0xDC2A0000u, 46u}, // kbx -> Latn
-    {0xE02A0000u,  1u}, // kby -> Arab
+    {0xE02A0000u,  2u}, // kby -> Arab
     {0x984A0000u, 46u}, // kcg -> Latn
     {0xA84A0000u, 46u}, // kck -> Latn
     {0xAC4A0000u, 46u}, // kcl -> Latn
     {0xCC4A0000u, 46u}, // kct -> Latn
     {0x906A0000u, 46u}, // kde -> Latn
-    {0x9C6A0000u,  1u}, // kdh -> Arab
+    {0x9C6A0000u,  2u}, // kdh -> Arab
     {0xAC6A0000u, 46u}, // kdl -> Latn
-    {0xCC6A0000u, 90u}, // kdt -> Thai
+    {0xCC6A0000u, 91u}, // kdt -> Thai
     {0x808A0000u, 46u}, // kea -> Latn
     {0xB48A0000u, 46u}, // ken -> Latn
     {0xE48A0000u, 46u}, // kez -> Latn
     {0xB8AA0000u, 46u}, // kfo -> Latn
-    {0xC4AA0000u, 18u}, // kfr -> Deva
-    {0xE0AA0000u, 18u}, // kfy -> Deva
+    {0xC4AA0000u, 19u}, // kfr -> Deva
+    {0xE0AA0000u, 19u}, // kfy -> Deva
     {0x6B670000u, 46u}, // kg -> Latn
     {0x90CA0000u, 46u}, // kge -> Latn
     {0x94CA0000u, 46u}, // kgf -> Latn
     {0xBCCA0000u, 46u}, // kgp -> Latn
     {0x80EA0000u, 46u}, // kha -> Latn
-    {0x84EA0000u, 83u}, // khb -> Talu
-    {0xB4EA0000u, 18u}, // khn -> Deva
+    {0x84EA0000u, 84u}, // khb -> Talu
+    {0xB4EA0000u, 19u}, // khn -> Deva
     {0xC0EA0000u, 46u}, // khq -> Latn
     {0xC8EA0000u, 46u}, // khs -> Latn
-    {0xCCEA0000u, 58u}, // kht -> Mymr
-    {0xD8EA0000u,  1u}, // khw -> Arab
+    {0xCCEA0000u, 59u}, // kht -> Mymr
+    {0xD8EA0000u,  2u}, // khw -> Arab
     {0xE4EA0000u, 46u}, // khz -> Latn
     {0x6B690000u, 46u}, // ki -> Latn
     {0xA50A0000u, 46u}, // kij -> Latn
@@ -693,11 +695,11 @@
     {0x992A0000u, 45u}, // kjg -> Laoo
     {0xC92A0000u, 46u}, // kjs -> Latn
     {0xE12A0000u, 46u}, // kjy -> Latn
-    {0x6B6B0000u, 17u}, // kk -> Cyrl
-    {0x6B6B4146u,  1u}, // kk-AF -> Arab
-    {0x6B6B434Eu,  1u}, // kk-CN -> Arab
-    {0x6B6B4952u,  1u}, // kk-IR -> Arab
-    {0x6B6B4D4Eu,  1u}, // kk-MN -> Arab
+    {0x6B6B0000u, 18u}, // kk -> Cyrl
+    {0x6B6B4146u,  2u}, // kk-AF -> Arab
+    {0x6B6B434Eu,  2u}, // kk-CN -> Arab
+    {0x6B6B4952u,  2u}, // kk-IR -> Arab
+    {0x6B6B4D4Eu,  2u}, // kk-MN -> Arab
     {0x894A0000u, 46u}, // kkc -> Latn
     {0xA54A0000u, 46u}, // kkj -> Latn
     {0x6B6C0000u, 46u}, // kl -> Latn
@@ -716,8 +718,8 @@
     {0x95AA0000u, 46u}, // knf -> Latn
     {0xBDAA0000u, 46u}, // knp -> Latn
     {0x6B6F0000u, 43u}, // ko -> Kore
-    {0xA1CA0000u, 17u}, // koi -> Cyrl
-    {0xA9CA0000u, 18u}, // kok -> Deva
+    {0xA1CA0000u, 18u}, // koi -> Cyrl
+    {0xA9CA0000u, 19u}, // kok -> Deva
     {0xADCA0000u, 46u}, // kol -> Latn
     {0xC9CA0000u, 46u}, // kos -> Latn
     {0xE5CA0000u, 46u}, // koz -> Latn
@@ -729,58 +731,58 @@
     {0x860A0000u, 46u}, // kqb -> Latn
     {0x960A0000u, 46u}, // kqf -> Latn
     {0xCA0A0000u, 46u}, // kqs -> Latn
-    {0xE20A0000u, 20u}, // kqy -> Ethi
+    {0xE20A0000u, 21u}, // kqy -> Ethi
     {0x6B720000u, 46u}, // kr -> Latn
-    {0x8A2A0000u, 17u}, // krc -> Cyrl
+    {0x8A2A0000u, 18u}, // krc -> Cyrl
     {0xA22A0000u, 46u}, // kri -> Latn
     {0xA62A0000u, 46u}, // krj -> Latn
     {0xAE2A0000u, 46u}, // krl -> Latn
     {0xCA2A0000u, 46u}, // krs -> Latn
-    {0xD22A0000u, 18u}, // kru -> Deva
-    {0x6B730000u,  1u}, // ks -> Arab
+    {0xD22A0000u, 19u}, // kru -> Deva
+    {0x6B730000u,  2u}, // ks -> Arab
     {0x864A0000u, 46u}, // ksb -> Latn
     {0x8E4A0000u, 46u}, // ksd -> Latn
     {0x964A0000u, 46u}, // ksf -> Latn
     {0x9E4A0000u, 46u}, // ksh -> Latn
     {0xA64A0000u, 46u}, // ksj -> Latn
     {0xC64A0000u, 46u}, // ksr -> Latn
-    {0x866A0000u, 20u}, // ktb -> Ethi
+    {0x866A0000u, 21u}, // ktb -> Ethi
     {0xB26A0000u, 46u}, // ktm -> Latn
     {0xBA6A0000u, 46u}, // kto -> Latn
     {0xC66A0000u, 46u}, // ktr -> Latn
     {0x6B750000u, 46u}, // ku -> Latn
-    {0x6B754952u,  1u}, // ku-IR -> Arab
-    {0x6B754C42u,  1u}, // ku-LB -> Arab
+    {0x6B754952u,  2u}, // ku-IR -> Arab
+    {0x6B754C42u,  2u}, // ku-LB -> Arab
     {0x868A0000u, 46u}, // kub -> Latn
     {0x8E8A0000u, 46u}, // kud -> Latn
     {0x928A0000u, 46u}, // kue -> Latn
     {0xA68A0000u, 46u}, // kuj -> Latn
-    {0xB28A0000u, 17u}, // kum -> Cyrl
+    {0xB28A0000u, 18u}, // kum -> Cyrl
     {0xB68A0000u, 46u}, // kun -> Latn
     {0xBE8A0000u, 46u}, // kup -> Latn
     {0xCA8A0000u, 46u}, // kus -> Latn
-    {0x6B760000u, 17u}, // kv -> Cyrl
+    {0x6B760000u, 18u}, // kv -> Cyrl
     {0x9AAA0000u, 46u}, // kvg -> Latn
     {0xC6AA0000u, 46u}, // kvr -> Latn
-    {0xDEAA0000u,  1u}, // kvx -> Arab
+    {0xDEAA0000u,  2u}, // kvx -> Arab
     {0x6B770000u, 46u}, // kw -> Latn
     {0xA6CA0000u, 46u}, // kwj -> Latn
     {0xBACA0000u, 46u}, // kwo -> Latn
     {0xC2CA0000u, 46u}, // kwq -> Latn
     {0x82EA0000u, 46u}, // kxa -> Latn
-    {0x8AEA0000u, 20u}, // kxc -> Ethi
+    {0x8AEA0000u, 21u}, // kxc -> Ethi
     {0x92EA0000u, 46u}, // kxe -> Latn
-    {0xAEEA0000u, 18u}, // kxl -> Deva
-    {0xB2EA0000u, 90u}, // kxm -> Thai
-    {0xBEEA0000u,  1u}, // kxp -> Arab
+    {0xAEEA0000u, 19u}, // kxl -> Deva
+    {0xB2EA0000u, 91u}, // kxm -> Thai
+    {0xBEEA0000u,  2u}, // kxp -> Arab
     {0xDAEA0000u, 46u}, // kxw -> Latn
     {0xE6EA0000u, 46u}, // kxz -> Latn
-    {0x6B790000u, 17u}, // ky -> Cyrl
-    {0x6B79434Eu,  1u}, // ky-CN -> Arab
+    {0x6B790000u, 18u}, // ky -> Cyrl
+    {0x6B79434Eu,  2u}, // ky-CN -> Arab
     {0x6B795452u, 46u}, // ky-TR -> Latn
     {0x930A0000u, 46u}, // kye -> Latn
     {0xDF0A0000u, 46u}, // kyx -> Latn
-    {0x9F2A0000u,  1u}, // kzh -> Arab
+    {0x9F2A0000u,  2u}, // kzh -> Arab
     {0xA72A0000u, 46u}, // kzj -> Latn
     {0xC72A0000u, 46u}, // kzr -> Latn
     {0xCF2A0000u, 46u}, // kzt -> Latn
@@ -788,15 +790,15 @@
     {0x840B0000u, 48u}, // lab -> Lina
     {0x8C0B0000u, 31u}, // lad -> Hebr
     {0x980B0000u, 46u}, // lag -> Latn
-    {0x9C0B0000u,  1u}, // lah -> Arab
+    {0x9C0B0000u,  2u}, // lah -> Arab
     {0xA40B0000u, 46u}, // laj -> Latn
     {0xC80B0000u, 46u}, // las -> Latn
     {0x6C620000u, 46u}, // lb -> Latn
-    {0x902B0000u, 17u}, // lbe -> Cyrl
+    {0x902B0000u, 18u}, // lbe -> Cyrl
     {0xD02B0000u, 46u}, // lbu -> Latn
     {0xD82B0000u, 46u}, // lbw -> Latn
     {0xB04B0000u, 46u}, // lcm -> Latn
-    {0xBC4B0000u, 90u}, // lcp -> Thai
+    {0xBC4B0000u, 91u}, // lcp -> Thai
     {0x846B0000u, 46u}, // ldb -> Latn
     {0x8C8B0000u, 46u}, // led -> Latn
     {0x908B0000u, 46u}, // lee -> Latn
@@ -804,23 +806,23 @@
     {0xBC8B0000u, 47u}, // lep -> Lepc
     {0xC08B0000u, 46u}, // leq -> Latn
     {0xD08B0000u, 46u}, // leu -> Latn
-    {0xE48B0000u, 17u}, // lez -> Cyrl
+    {0xE48B0000u, 18u}, // lez -> Cyrl
     {0x6C670000u, 46u}, // lg -> Latn
     {0x98CB0000u, 46u}, // lgg -> Latn
     {0x6C690000u, 46u}, // li -> Latn
     {0x810B0000u, 46u}, // lia -> Latn
     {0x8D0B0000u, 46u}, // lid -> Latn
-    {0x950B0000u, 18u}, // lif -> Deva
+    {0x950B0000u, 19u}, // lif -> Deva
     {0x990B0000u, 46u}, // lig -> Latn
     {0x9D0B0000u, 46u}, // lih -> Latn
     {0xA50B0000u, 46u}, // lij -> Latn
     {0xC90B0000u, 49u}, // lis -> Lisu
     {0xBD2B0000u, 46u}, // ljp -> Latn
-    {0xA14B0000u,  1u}, // lki -> Arab
+    {0xA14B0000u,  2u}, // lki -> Arab
     {0xCD4B0000u, 46u}, // lkt -> Latn
     {0x916B0000u, 46u}, // lle -> Latn
     {0xB56B0000u, 46u}, // lln -> Latn
-    {0xB58B0000u, 87u}, // lmn -> Telu
+    {0xB58B0000u, 88u}, // lmn -> Telu
     {0xB98B0000u, 46u}, // lmo -> Latn
     {0xBD8B0000u, 46u}, // lmp -> Latn
     {0x6C6E0000u, 46u}, // ln -> Latn
@@ -833,25 +835,25 @@
     {0xC5CB0000u, 46u}, // lor -> Latn
     {0xC9CB0000u, 46u}, // los -> Latn
     {0xE5CB0000u, 46u}, // loz -> Latn
-    {0x8A2B0000u,  1u}, // lrc -> Arab
+    {0x8A2B0000u,  2u}, // lrc -> Arab
     {0x6C740000u, 46u}, // lt -> Latn
     {0x9A6B0000u, 46u}, // ltg -> Latn
     {0x6C750000u, 46u}, // lu -> Latn
     {0x828B0000u, 46u}, // lua -> Latn
     {0xBA8B0000u, 46u}, // luo -> Latn
     {0xE28B0000u, 46u}, // luy -> Latn
-    {0xE68B0000u,  1u}, // luz -> Arab
+    {0xE68B0000u,  2u}, // luz -> Arab
     {0x6C760000u, 46u}, // lv -> Latn
-    {0xAECB0000u, 90u}, // lwl -> Thai
-    {0x9F2B0000u, 28u}, // lzh -> Hans
+    {0xAECB0000u, 91u}, // lwl -> Thai
+    {0x9F2B0000u, 29u}, // lzh -> Hans
     {0xE72B0000u, 46u}, // lzz -> Latn
     {0x8C0C0000u, 46u}, // mad -> Latn
     {0x940C0000u, 46u}, // maf -> Latn
-    {0x980C0000u, 18u}, // mag -> Deva
-    {0xA00C0000u, 18u}, // mai -> Deva
+    {0x980C0000u, 19u}, // mag -> Deva
+    {0xA00C0000u, 19u}, // mai -> Deva
     {0xA80C0000u, 46u}, // mak -> Latn
     {0xB40C0000u, 46u}, // man -> Latn
-    {0xB40C474Eu, 60u}, // man-GN -> Nkoo
+    {0xB40C474Eu, 61u}, // man-GN -> Nkoo
     {0xC80C0000u, 46u}, // mas -> Latn
     {0xD80C0000u, 46u}, // maw -> Latn
     {0xE40C0000u, 46u}, // maz -> Latn
@@ -866,12 +868,12 @@
     {0xC44C0000u, 46u}, // mcr -> Latn
     {0xD04C0000u, 46u}, // mcu -> Latn
     {0x806C0000u, 46u}, // mda -> Latn
-    {0x906C0000u,  1u}, // mde -> Arab
-    {0x946C0000u, 17u}, // mdf -> Cyrl
+    {0x906C0000u,  2u}, // mde -> Arab
+    {0x946C0000u, 18u}, // mdf -> Cyrl
     {0x9C6C0000u, 46u}, // mdh -> Latn
     {0xA46C0000u, 46u}, // mdj -> Latn
     {0xC46C0000u, 46u}, // mdr -> Latn
-    {0xDC6C0000u, 20u}, // mdx -> Ethi
+    {0xDC6C0000u, 21u}, // mdx -> Ethi
     {0x8C8C0000u, 46u}, // med -> Latn
     {0x908C0000u, 46u}, // mee -> Latn
     {0xA88C0000u, 46u}, // mek -> Latn
@@ -879,7 +881,7 @@
     {0xC48C0000u, 46u}, // mer -> Latn
     {0xCC8C0000u, 46u}, // met -> Latn
     {0xD08C0000u, 46u}, // meu -> Latn
-    {0x80AC0000u,  1u}, // mfa -> Arab
+    {0x80AC0000u,  2u}, // mfa -> Arab
     {0x90AC0000u, 46u}, // mfe -> Latn
     {0xB4AC0000u, 46u}, // mfn -> Latn
     {0xB8AC0000u, 46u}, // mfo -> Latn
@@ -888,7 +890,7 @@
     {0x9CCC0000u, 46u}, // mgh -> Latn
     {0xACCC0000u, 46u}, // mgl -> Latn
     {0xB8CC0000u, 46u}, // mgo -> Latn
-    {0xBCCC0000u, 18u}, // mgp -> Deva
+    {0xBCCC0000u, 19u}, // mgp -> Deva
     {0xE0CC0000u, 46u}, // mgy -> Latn
     {0x6D680000u, 46u}, // mh -> Latn
     {0xA0EC0000u, 46u}, // mhi -> Latn
@@ -896,26 +898,25 @@
     {0x6D690000u, 46u}, // mi -> Latn
     {0x950C0000u, 46u}, // mif -> Latn
     {0xB50C0000u, 46u}, // min -> Latn
-    {0xC90C0000u, 30u}, // mis -> Hatr
     {0xD90C0000u, 46u}, // miw -> Latn
-    {0x6D6B0000u, 17u}, // mk -> Cyrl
-    {0xA14C0000u,  1u}, // mki -> Arab
+    {0x6D6B0000u, 18u}, // mk -> Cyrl
+    {0xA14C0000u,  2u}, // mki -> Arab
     {0xAD4C0000u, 46u}, // mkl -> Latn
     {0xBD4C0000u, 46u}, // mkp -> Latn
     {0xD94C0000u, 46u}, // mkw -> Latn
-    {0x6D6C0000u, 55u}, // ml -> Mlym
+    {0x6D6C0000u, 56u}, // ml -> Mlym
     {0x916C0000u, 46u}, // mle -> Latn
     {0xBD6C0000u, 46u}, // mlp -> Latn
     {0xC96C0000u, 46u}, // mls -> Latn
     {0xB98C0000u, 46u}, // mmo -> Latn
     {0xD18C0000u, 46u}, // mmu -> Latn
     {0xDD8C0000u, 46u}, // mmx -> Latn
-    {0x6D6E0000u, 17u}, // mn -> Cyrl
-    {0x6D6E434Eu, 56u}, // mn-CN -> Mong
+    {0x6D6E0000u, 18u}, // mn -> Cyrl
+    {0x6D6E434Eu, 57u}, // mn-CN -> Mong
     {0x81AC0000u, 46u}, // mna -> Latn
     {0x95AC0000u, 46u}, // mnf -> Latn
-    {0xA1AC0000u,  7u}, // mni -> Beng
-    {0xD9AC0000u, 58u}, // mnw -> Mymr
+    {0xA1AC0000u,  8u}, // mni -> Beng
+    {0xD9AC0000u, 59u}, // mnw -> Mymr
     {0x6D6F0000u, 46u}, // mo -> Latn
     {0x81CC0000u, 46u}, // moa -> Latn
     {0x91CC0000u, 46u}, // moe -> Latn
@@ -927,39 +928,39 @@
     {0xCDEC0000u, 46u}, // mpt -> Latn
     {0xDDEC0000u, 46u}, // mpx -> Latn
     {0xAE0C0000u, 46u}, // mql -> Latn
-    {0x6D720000u, 18u}, // mr -> Deva
-    {0x8E2C0000u, 18u}, // mrd -> Deva
-    {0xA62C0000u, 17u}, // mrj -> Cyrl
-    {0xBA2C0000u, 57u}, // mro -> Mroo
+    {0x6D720000u, 19u}, // mr -> Deva
+    {0x8E2C0000u, 19u}, // mrd -> Deva
+    {0xA62C0000u, 18u}, // mrj -> Cyrl
+    {0xBA2C0000u, 58u}, // mro -> Mroo
     {0x6D730000u, 46u}, // ms -> Latn
-    {0x6D734343u,  1u}, // ms-CC -> Arab
+    {0x6D734343u,  2u}, // ms-CC -> Arab
     {0x6D740000u, 46u}, // mt -> Latn
     {0x8A6C0000u, 46u}, // mtc -> Latn
     {0x966C0000u, 46u}, // mtf -> Latn
     {0xA26C0000u, 46u}, // mti -> Latn
-    {0xC66C0000u, 18u}, // mtr -> Deva
+    {0xC66C0000u, 19u}, // mtr -> Deva
     {0x828C0000u, 46u}, // mua -> Latn
     {0xC68C0000u, 46u}, // mur -> Latn
     {0xCA8C0000u, 46u}, // mus -> Latn
     {0x82AC0000u, 46u}, // mva -> Latn
     {0xB6AC0000u, 46u}, // mvn -> Latn
-    {0xE2AC0000u,  1u}, // mvy -> Arab
+    {0xE2AC0000u,  2u}, // mvy -> Arab
     {0xAACC0000u, 46u}, // mwk -> Latn
-    {0xC6CC0000u, 18u}, // mwr -> Deva
+    {0xC6CC0000u, 19u}, // mwr -> Deva
     {0xD6CC0000u, 46u}, // mwv -> Latn
     {0xDACC0000u, 34u}, // mww -> Hmnp
     {0x8AEC0000u, 46u}, // mxc -> Latn
     {0xB2EC0000u, 46u}, // mxm -> Latn
-    {0x6D790000u, 58u}, // my -> Mymr
+    {0x6D790000u, 59u}, // my -> Mymr
     {0xAB0C0000u, 46u}, // myk -> Latn
-    {0xB30C0000u, 20u}, // mym -> Ethi
-    {0xD70C0000u, 17u}, // myv -> Cyrl
+    {0xB30C0000u, 21u}, // mym -> Ethi
+    {0xD70C0000u, 18u}, // myv -> Cyrl
     {0xDB0C0000u, 46u}, // myw -> Latn
     {0xDF0C0000u, 46u}, // myx -> Latn
     {0xE70C0000u, 52u}, // myz -> Mand
     {0xAB2C0000u, 46u}, // mzk -> Latn
     {0xB32C0000u, 46u}, // mzm -> Latn
-    {0xB72C0000u,  1u}, // mzn -> Arab
+    {0xB72C0000u,  2u}, // mzn -> Arab
     {0xBF2C0000u, 46u}, // mzp -> Latn
     {0xDB2C0000u, 46u}, // mzw -> Latn
     {0xE72C0000u, 46u}, // mzz -> Latn
@@ -967,7 +968,7 @@
     {0x880D0000u, 46u}, // nac -> Latn
     {0x940D0000u, 46u}, // naf -> Latn
     {0xA80D0000u, 46u}, // nak -> Latn
-    {0xB40D0000u, 28u}, // nan -> Hans
+    {0xB40D0000u, 29u}, // nan -> Hans
     {0xBC0D0000u, 46u}, // nap -> Latn
     {0xC00D0000u, 46u}, // naq -> Latn
     {0xC80D0000u, 46u}, // nas -> Latn
@@ -981,9 +982,9 @@
     {0x6E640000u, 46u}, // nd -> Latn
     {0x886D0000u, 46u}, // ndc -> Latn
     {0xC86D0000u, 46u}, // nds -> Latn
-    {0x6E650000u, 18u}, // ne -> Deva
+    {0x6E650000u, 19u}, // ne -> Deva
     {0x848D0000u, 46u}, // neb -> Latn
-    {0xD88D0000u, 18u}, // new -> Deva
+    {0xD88D0000u, 19u}, // new -> Deva
     {0xDC8D0000u, 46u}, // nex -> Latn
     {0xC4AD0000u, 46u}, // nfr -> Latn
     {0x6E670000u, 46u}, // ng -> Latn
@@ -1011,17 +1012,17 @@
     {0x9DAD0000u, 46u}, // nnh -> Latn
     {0xA9AD0000u, 46u}, // nnk -> Latn
     {0xB1AD0000u, 46u}, // nnm -> Latn
-    {0xBDAD0000u, 94u}, // nnp -> Wcho
+    {0xBDAD0000u, 95u}, // nnp -> Wcho
     {0x6E6F0000u, 46u}, // no -> Latn
     {0x8DCD0000u, 44u}, // nod -> Lana
-    {0x91CD0000u, 18u}, // noe -> Deva
-    {0xB5CD0000u, 72u}, // non -> Runr
+    {0x91CD0000u, 19u}, // noe -> Deva
+    {0xB5CD0000u, 73u}, // non -> Runr
     {0xBDCD0000u, 46u}, // nop -> Latn
     {0xD1CD0000u, 46u}, // nou -> Latn
-    {0xBA0D0000u, 60u}, // nqo -> Nkoo
+    {0xBA0D0000u, 61u}, // nqo -> Nkoo
     {0x6E720000u, 46u}, // nr -> Latn
     {0x862D0000u, 46u}, // nrb -> Latn
-    {0xAA4D0000u, 10u}, // nsk -> Cans
+    {0xAA4D0000u, 11u}, // nsk -> Cans
     {0xB64D0000u, 46u}, // nsn -> Latn
     {0xBA4D0000u, 46u}, // nso -> Latn
     {0xCA4D0000u, 46u}, // nss -> Latn
@@ -1049,18 +1050,18 @@
     {0xB5AE0000u, 46u}, // onn -> Latn
     {0xC9AE0000u, 46u}, // ons -> Latn
     {0xB1EE0000u, 46u}, // opm -> Latn
-    {0x6F720000u, 65u}, // or -> Orya
+    {0x6F720000u, 66u}, // or -> Orya
     {0xBA2E0000u, 46u}, // oro -> Latn
-    {0xD22E0000u,  1u}, // oru -> Arab
-    {0x6F730000u, 17u}, // os -> Cyrl
-    {0x824E0000u, 66u}, // osa -> Osge
-    {0x826E0000u,  1u}, // ota -> Arab
-    {0xAA6E0000u, 64u}, // otk -> Orkh
+    {0xD22E0000u,  2u}, // oru -> Arab
+    {0x6F730000u, 18u}, // os -> Cyrl
+    {0x824E0000u, 67u}, // osa -> Osge
+    {0x826E0000u,  2u}, // ota -> Arab
+    {0xAA6E0000u, 65u}, // otk -> Orkh
     {0xB32E0000u, 46u}, // ozm -> Latn
-    {0x70610000u, 27u}, // pa -> Guru
-    {0x7061504Bu,  1u}, // pa-PK -> Arab
+    {0x70610000u, 28u}, // pa -> Guru
+    {0x7061504Bu,  2u}, // pa-PK -> Arab
     {0x980F0000u, 46u}, // pag -> Latn
-    {0xAC0F0000u, 68u}, // pal -> Phli
+    {0xAC0F0000u, 69u}, // pal -> Phli
     {0xB00F0000u, 46u}, // pam -> Latn
     {0xBC0F0000u, 46u}, // pap -> Latn
     {0xD00F0000u, 46u}, // pau -> Latn
@@ -1070,28 +1071,28 @@
     {0x886F0000u, 46u}, // pdc -> Latn
     {0xCC6F0000u, 46u}, // pdt -> Latn
     {0x8C8F0000u, 46u}, // ped -> Latn
-    {0xB88F0000u, 95u}, // peo -> Xpeo
+    {0xB88F0000u, 96u}, // peo -> Xpeo
     {0xDC8F0000u, 46u}, // pex -> Latn
     {0xACAF0000u, 46u}, // pfl -> Latn
-    {0xACEF0000u,  1u}, // phl -> Arab
-    {0xB4EF0000u, 69u}, // phn -> Phnx
+    {0xACEF0000u,  2u}, // phl -> Arab
+    {0xB4EF0000u, 70u}, // phn -> Phnx
     {0xAD0F0000u, 46u}, // pil -> Latn
     {0xBD0F0000u, 46u}, // pip -> Latn
-    {0x814F0000u,  8u}, // pka -> Brah
+    {0x814F0000u,  9u}, // pka -> Brah
     {0xB94F0000u, 46u}, // pko -> Latn
     {0x706C0000u, 46u}, // pl -> Latn
     {0x816F0000u, 46u}, // pla -> Latn
     {0xC98F0000u, 46u}, // pms -> Latn
     {0x99AF0000u, 46u}, // png -> Latn
     {0xB5AF0000u, 46u}, // pnn -> Latn
-    {0xCDAF0000u, 25u}, // pnt -> Grek
+    {0xCDAF0000u, 26u}, // pnt -> Grek
     {0xB5CF0000u, 46u}, // pon -> Latn
-    {0x81EF0000u, 18u}, // ppa -> Deva
+    {0x81EF0000u, 19u}, // ppa -> Deva
     {0xB9EF0000u, 46u}, // ppo -> Latn
     {0x822F0000u, 39u}, // pra -> Khar
-    {0x8E2F0000u,  1u}, // prd -> Arab
+    {0x8E2F0000u,  2u}, // prd -> Arab
     {0x9A2F0000u, 46u}, // prg -> Latn
-    {0x70730000u,  1u}, // ps -> Arab
+    {0x70730000u,  2u}, // ps -> Arab
     {0xCA4F0000u, 46u}, // pss -> Latn
     {0x70740000u, 46u}, // pt -> Latn
     {0xBE6F0000u, 46u}, // ptp -> Latn
@@ -1101,23 +1102,23 @@
     {0x8A900000u, 46u}, // quc -> Latn
     {0x9A900000u, 46u}, // qug -> Latn
     {0xA0110000u, 46u}, // rai -> Latn
-    {0xA4110000u, 18u}, // raj -> Deva
+    {0xA4110000u, 19u}, // raj -> Deva
     {0xB8110000u, 46u}, // rao -> Latn
     {0x94510000u, 46u}, // rcf -> Latn
     {0xA4910000u, 46u}, // rej -> Latn
     {0xAC910000u, 46u}, // rel -> Latn
     {0xC8910000u, 46u}, // res -> Latn
     {0xB4D10000u, 46u}, // rgn -> Latn
-    {0x98F10000u,  1u}, // rhg -> Arab
+    {0x98F10000u,  2u}, // rhg -> Arab
     {0x81110000u, 46u}, // ria -> Latn
-    {0x95110000u, 88u}, // rif -> Tfng
+    {0x95110000u, 89u}, // rif -> Tfng
     {0x95114E4Cu, 46u}, // rif-NL -> Latn
-    {0xC9310000u, 18u}, // rjs -> Deva
-    {0xCD510000u,  7u}, // rkt -> Beng
+    {0xC9310000u, 19u}, // rjs -> Deva
+    {0xCD510000u,  8u}, // rkt -> Beng
     {0x726D0000u, 46u}, // rm -> Latn
     {0x95910000u, 46u}, // rmf -> Latn
     {0xB9910000u, 46u}, // rmo -> Latn
-    {0xCD910000u,  1u}, // rmt -> Arab
+    {0xCD910000u,  2u}, // rmt -> Arab
     {0xD1910000u, 46u}, // rmu -> Latn
     {0x726E0000u, 46u}, // rn -> Latn
     {0x81B10000u, 46u}, // rna -> Latn
@@ -1128,49 +1129,49 @@
     {0xB9D10000u, 46u}, // roo -> Latn
     {0xBA310000u, 46u}, // rro -> Latn
     {0xB2710000u, 46u}, // rtm -> Latn
-    {0x72750000u, 17u}, // ru -> Cyrl
-    {0x92910000u, 17u}, // rue -> Cyrl
+    {0x72750000u, 18u}, // ru -> Cyrl
+    {0x92910000u, 18u}, // rue -> Cyrl
     {0x9A910000u, 46u}, // rug -> Latn
     {0x72770000u, 46u}, // rw -> Latn
     {0xAAD10000u, 46u}, // rwk -> Latn
     {0xBAD10000u, 46u}, // rwo -> Latn
     {0xD3110000u, 38u}, // ryu -> Kana
-    {0x73610000u, 18u}, // sa -> Deva
+    {0x73610000u, 19u}, // sa -> Deva
     {0x94120000u, 46u}, // saf -> Latn
-    {0x9C120000u, 17u}, // sah -> Cyrl
+    {0x9C120000u, 18u}, // sah -> Cyrl
     {0xC0120000u, 46u}, // saq -> Latn
     {0xC8120000u, 46u}, // sas -> Latn
-    {0xCC120000u, 63u}, // sat -> Olck
+    {0xCC120000u, 64u}, // sat -> Olck
     {0xD4120000u, 46u}, // sav -> Latn
-    {0xE4120000u, 75u}, // saz -> Saur
+    {0xE4120000u, 76u}, // saz -> Saur
     {0x80320000u, 46u}, // sba -> Latn
     {0x90320000u, 46u}, // sbe -> Latn
     {0xBC320000u, 46u}, // sbp -> Latn
     {0x73630000u, 46u}, // sc -> Latn
-    {0xA8520000u, 18u}, // sck -> Deva
-    {0xAC520000u,  1u}, // scl -> Arab
+    {0xA8520000u, 19u}, // sck -> Deva
+    {0xAC520000u,  2u}, // scl -> Arab
     {0xB4520000u, 46u}, // scn -> Latn
     {0xB8520000u, 46u}, // sco -> Latn
     {0xC8520000u, 46u}, // scs -> Latn
-    {0x73640000u,  1u}, // sd -> Arab
+    {0x73640000u,  2u}, // sd -> Arab
     {0x88720000u, 46u}, // sdc -> Latn
-    {0x9C720000u,  1u}, // sdh -> Arab
+    {0x9C720000u,  2u}, // sdh -> Arab
     {0x73650000u, 46u}, // se -> Latn
     {0x94920000u, 46u}, // sef -> Latn
     {0x9C920000u, 46u}, // seh -> Latn
     {0xA0920000u, 46u}, // sei -> Latn
     {0xC8920000u, 46u}, // ses -> Latn
     {0x73670000u, 46u}, // sg -> Latn
-    {0x80D20000u, 62u}, // sga -> Ogam
+    {0x80D20000u, 63u}, // sga -> Ogam
     {0xC8D20000u, 46u}, // sgs -> Latn
-    {0xD8D20000u, 20u}, // sgw -> Ethi
+    {0xD8D20000u, 21u}, // sgw -> Ethi
     {0xE4D20000u, 46u}, // sgz -> Latn
     {0x73680000u, 46u}, // sh -> Latn
-    {0xA0F20000u, 88u}, // shi -> Tfng
+    {0xA0F20000u, 89u}, // shi -> Tfng
     {0xA8F20000u, 46u}, // shk -> Latn
-    {0xB4F20000u, 58u}, // shn -> Mymr
-    {0xD0F20000u,  1u}, // shu -> Arab
-    {0x73690000u, 77u}, // si -> Sinh
+    {0xB4F20000u, 59u}, // shn -> Mymr
+    {0xD0F20000u,  2u}, // shu -> Arab
+    {0x73690000u, 78u}, // si -> Sinh
     {0x8D120000u, 46u}, // sid -> Latn
     {0x99120000u, 46u}, // sig -> Latn
     {0xAD120000u, 46u}, // sil -> Latn
@@ -1178,7 +1179,7 @@
     {0xC5320000u, 46u}, // sjr -> Latn
     {0x736B0000u, 46u}, // sk -> Latn
     {0x89520000u, 46u}, // skc -> Latn
-    {0xC5520000u,  1u}, // skr -> Arab
+    {0xC5520000u,  2u}, // skr -> Arab
     {0xC9520000u, 46u}, // sks -> Latn
     {0x736C0000u, 46u}, // sl -> Latn
     {0x8D720000u, 46u}, // sld -> Latn
@@ -1189,7 +1190,7 @@
     {0x81920000u, 46u}, // sma -> Latn
     {0xA5920000u, 46u}, // smj -> Latn
     {0xB5920000u, 46u}, // smn -> Latn
-    {0xBD920000u, 73u}, // smp -> Samr
+    {0xBD920000u, 74u}, // smp -> Samr
     {0xC1920000u, 46u}, // smq -> Latn
     {0xC9920000u, 46u}, // sms -> Latn
     {0x736E0000u, 46u}, // sn -> Latn
@@ -1199,24 +1200,24 @@
     {0xDDB20000u, 46u}, // snx -> Latn
     {0xE1B20000u, 46u}, // sny -> Latn
     {0x736F0000u, 46u}, // so -> Latn
-    {0x99D20000u, 78u}, // sog -> Sogd
+    {0x99D20000u, 79u}, // sog -> Sogd
     {0xA9D20000u, 46u}, // sok -> Latn
     {0xC1D20000u, 46u}, // soq -> Latn
-    {0xD1D20000u, 90u}, // sou -> Thai
+    {0xD1D20000u, 91u}, // sou -> Thai
     {0xE1D20000u, 46u}, // soy -> Latn
     {0x8DF20000u, 46u}, // spd -> Latn
     {0xADF20000u, 46u}, // spl -> Latn
     {0xC9F20000u, 46u}, // sps -> Latn
     {0x73710000u, 46u}, // sq -> Latn
-    {0x73720000u, 17u}, // sr -> Cyrl
+    {0x73720000u, 18u}, // sr -> Cyrl
     {0x73724D45u, 46u}, // sr-ME -> Latn
     {0x7372524Fu, 46u}, // sr-RO -> Latn
     {0x73725255u, 46u}, // sr-RU -> Latn
     {0x73725452u, 46u}, // sr-TR -> Latn
-    {0x86320000u, 79u}, // srb -> Sora
+    {0x86320000u, 80u}, // srb -> Sora
     {0xB6320000u, 46u}, // srn -> Latn
     {0xC6320000u, 46u}, // srr -> Latn
-    {0xDE320000u, 18u}, // srx -> Deva
+    {0xDE320000u, 19u}, // srx -> Deva
     {0x73730000u, 46u}, // ss -> Latn
     {0x8E520000u, 46u}, // ssd -> Latn
     {0x9A520000u, 46u}, // ssg -> Latn
@@ -1232,18 +1233,18 @@
     {0xCA920000u, 46u}, // sus -> Latn
     {0x73760000u, 46u}, // sv -> Latn
     {0x73770000u, 46u}, // sw -> Latn
-    {0x86D20000u,  1u}, // swb -> Arab
+    {0x86D20000u,  2u}, // swb -> Arab
     {0x8AD20000u, 46u}, // swc -> Latn
     {0x9AD20000u, 46u}, // swg -> Latn
     {0xBED20000u, 46u}, // swp -> Latn
-    {0xD6D20000u, 18u}, // swv -> Deva
+    {0xD6D20000u, 19u}, // swv -> Deva
     {0xB6F20000u, 46u}, // sxn -> Latn
     {0xDAF20000u, 46u}, // sxw -> Latn
-    {0xAF120000u,  7u}, // syl -> Beng
-    {0xC7120000u, 81u}, // syr -> Syrc
+    {0xAF120000u,  8u}, // syl -> Beng
+    {0xC7120000u, 82u}, // syr -> Syrc
     {0xAF320000u, 46u}, // szl -> Latn
-    {0x74610000u, 84u}, // ta -> Taml
-    {0xA4130000u, 18u}, // taj -> Deva
+    {0x74610000u, 85u}, // ta -> Taml
+    {0xA4130000u, 19u}, // taj -> Deva
     {0xAC130000u, 46u}, // tal -> Latn
     {0xB4130000u, 46u}, // tan -> Latn
     {0xC0130000u, 46u}, // taq -> Latn
@@ -1256,28 +1257,28 @@
     {0xE4330000u, 46u}, // tbz -> Latn
     {0xA0530000u, 46u}, // tci -> Latn
     {0xE0530000u, 42u}, // tcy -> Knda
-    {0x8C730000u, 82u}, // tdd -> Tale
-    {0x98730000u, 18u}, // tdg -> Deva
-    {0x9C730000u, 18u}, // tdh -> Deva
+    {0x8C730000u, 83u}, // tdd -> Tale
+    {0x98730000u, 19u}, // tdg -> Deva
+    {0x9C730000u, 19u}, // tdh -> Deva
     {0xD0730000u, 46u}, // tdu -> Latn
-    {0x74650000u, 87u}, // te -> Telu
+    {0x74650000u, 88u}, // te -> Telu
     {0x8C930000u, 46u}, // ted -> Latn
     {0xB0930000u, 46u}, // tem -> Latn
     {0xB8930000u, 46u}, // teo -> Latn
     {0xCC930000u, 46u}, // tet -> Latn
     {0xA0B30000u, 46u}, // tfi -> Latn
-    {0x74670000u, 17u}, // tg -> Cyrl
-    {0x7467504Bu,  1u}, // tg-PK -> Arab
+    {0x74670000u, 18u}, // tg -> Cyrl
+    {0x7467504Bu,  2u}, // tg-PK -> Arab
     {0x88D30000u, 46u}, // tgc -> Latn
     {0xB8D30000u, 46u}, // tgo -> Latn
     {0xD0D30000u, 46u}, // tgu -> Latn
-    {0x74680000u, 90u}, // th -> Thai
-    {0xACF30000u, 18u}, // thl -> Deva
-    {0xC0F30000u, 18u}, // thq -> Deva
-    {0xC4F30000u, 18u}, // thr -> Deva
-    {0x74690000u, 20u}, // ti -> Ethi
+    {0x74680000u, 91u}, // th -> Thai
+    {0xACF30000u, 19u}, // thl -> Deva
+    {0xC0F30000u, 19u}, // thq -> Deva
+    {0xC4F30000u, 19u}, // thr -> Deva
+    {0x74690000u, 21u}, // ti -> Ethi
     {0x95130000u, 46u}, // tif -> Latn
-    {0x99130000u, 20u}, // tig -> Ethi
+    {0x99130000u, 21u}, // tig -> Ethi
     {0xA9130000u, 46u}, // tik -> Latn
     {0xB1130000u, 46u}, // tim -> Latn
     {0xB9130000u, 46u}, // tio -> Latn
@@ -1285,7 +1286,7 @@
     {0x746B0000u, 46u}, // tk -> Latn
     {0xAD530000u, 46u}, // tkl -> Latn
     {0xC5530000u, 46u}, // tkr -> Latn
-    {0xCD530000u, 18u}, // tkt -> Deva
+    {0xCD530000u, 19u}, // tkt -> Deva
     {0x746C0000u, 46u}, // tl -> Latn
     {0x95730000u, 46u}, // tlf -> Latn
     {0xDD730000u, 46u}, // tlx -> Latn
@@ -1305,19 +1306,19 @@
     {0x74720000u, 46u}, // tr -> Latn
     {0xD2330000u, 46u}, // tru -> Latn
     {0xD6330000u, 46u}, // trv -> Latn
-    {0xDA330000u,  1u}, // trw -> Arab
+    {0xDA330000u,  2u}, // trw -> Arab
     {0x74730000u, 46u}, // ts -> Latn
-    {0x8E530000u, 25u}, // tsd -> Grek
-    {0x96530000u, 18u}, // tsf -> Deva
+    {0x8E530000u, 26u}, // tsd -> Grek
+    {0x96530000u, 19u}, // tsf -> Deva
     {0x9A530000u, 46u}, // tsg -> Latn
-    {0xA6530000u, 91u}, // tsj -> Tibt
+    {0xA6530000u, 92u}, // tsj -> Tibt
     {0xDA530000u, 46u}, // tsw -> Latn
-    {0x74740000u, 17u}, // tt -> Cyrl
+    {0x74740000u, 18u}, // tt -> Cyrl
     {0x8E730000u, 46u}, // ttd -> Latn
     {0x92730000u, 46u}, // tte -> Latn
     {0xA6730000u, 46u}, // ttj -> Latn
     {0xC6730000u, 46u}, // ttr -> Latn
-    {0xCA730000u, 90u}, // tts -> Thai
+    {0xCA730000u, 91u}, // tts -> Thai
     {0xCE730000u, 46u}, // ttt -> Latn
     {0x9E930000u, 46u}, // tuh -> Latn
     {0xAE930000u, 46u}, // tul -> Latn
@@ -1328,25 +1329,26 @@
     {0xD2B30000u, 46u}, // tvu -> Latn
     {0x9ED30000u, 46u}, // twh -> Latn
     {0xC2D30000u, 46u}, // twq -> Latn
-    {0x9AF30000u, 85u}, // txg -> Tang
+    {0x9AF30000u, 86u}, // txg -> Tang
     {0x74790000u, 46u}, // ty -> Latn
     {0x83130000u, 46u}, // tya -> Latn
-    {0xD7130000u, 17u}, // tyv -> Cyrl
+    {0xD7130000u, 18u}, // tyv -> Cyrl
     {0xB3330000u, 46u}, // tzm -> Latn
     {0xD0340000u, 46u}, // ubu -> Latn
-    {0xB0740000u, 17u}, // udm -> Cyrl
-    {0x75670000u,  1u}, // ug -> Arab
-    {0x75674B5Au, 17u}, // ug-KZ -> Cyrl
-    {0x75674D4Eu, 17u}, // ug-MN -> Cyrl
-    {0x80D40000u, 92u}, // uga -> Ugar
-    {0x756B0000u, 17u}, // uk -> Cyrl
+    {0xA0740000u,  0u}, // udi -> Aghb
+    {0xB0740000u, 18u}, // udm -> Cyrl
+    {0x75670000u,  2u}, // ug -> Arab
+    {0x75674B5Au, 18u}, // ug-KZ -> Cyrl
+    {0x75674D4Eu, 18u}, // ug-MN -> Cyrl
+    {0x80D40000u, 93u}, // uga -> Ugar
+    {0x756B0000u, 18u}, // uk -> Cyrl
     {0xA1740000u, 46u}, // uli -> Latn
     {0x85940000u, 46u}, // umb -> Latn
-    {0xC5B40000u,  7u}, // unr -> Beng
-    {0xC5B44E50u, 18u}, // unr-NP -> Deva
-    {0xDDB40000u,  7u}, // unx -> Beng
+    {0xC5B40000u,  8u}, // unr -> Beng
+    {0xC5B44E50u, 19u}, // unr-NP -> Deva
+    {0xDDB40000u,  8u}, // unx -> Beng
     {0xA9D40000u, 46u}, // uok -> Latn
-    {0x75720000u,  1u}, // ur -> Arab
+    {0x75720000u,  2u}, // ur -> Arab
     {0xA2340000u, 46u}, // uri -> Latn
     {0xCE340000u, 46u}, // urt -> Latn
     {0xDA340000u, 46u}, // urw -> Latn
@@ -1356,10 +1358,10 @@
     {0x9EB40000u, 46u}, // uvh -> Latn
     {0xAEB40000u, 46u}, // uvl -> Latn
     {0x757A0000u, 46u}, // uz -> Latn
-    {0x757A4146u,  1u}, // uz-AF -> Arab
-    {0x757A434Eu, 17u}, // uz-CN -> Cyrl
+    {0x757A4146u,  2u}, // uz-AF -> Arab
+    {0x757A434Eu, 18u}, // uz-CN -> Cyrl
     {0x98150000u, 46u}, // vag -> Latn
-    {0xA0150000u, 93u}, // vai -> Vaii
+    {0xA0150000u, 94u}, // vai -> Vaii
     {0xB4150000u, 46u}, // van -> Latn
     {0x76650000u, 46u}, // ve -> Latn
     {0x88950000u, 46u}, // vec -> Latn
@@ -1378,12 +1380,12 @@
     {0x77610000u, 46u}, // wa -> Latn
     {0x90160000u, 46u}, // wae -> Latn
     {0xA4160000u, 46u}, // waj -> Latn
-    {0xAC160000u, 20u}, // wal -> Ethi
+    {0xAC160000u, 21u}, // wal -> Ethi
     {0xB4160000u, 46u}, // wan -> Latn
     {0xC4160000u, 46u}, // war -> Latn
     {0xBC360000u, 46u}, // wbp -> Latn
-    {0xC0360000u, 87u}, // wbq -> Telu
-    {0xC4360000u, 18u}, // wbr -> Deva
+    {0xC0360000u, 88u}, // wbq -> Telu
+    {0xC4360000u, 19u}, // wbr -> Deva
     {0xA0560000u, 46u}, // wci -> Latn
     {0xC4960000u, 46u}, // wer -> Latn
     {0xA0D60000u, 46u}, // wgi -> Latn
@@ -1396,40 +1398,40 @@
     {0xC9760000u, 46u}, // wls -> Latn
     {0xB9960000u, 46u}, // wmo -> Latn
     {0x89B60000u, 46u}, // wnc -> Latn
-    {0xA1B60000u,  1u}, // wni -> Arab
+    {0xA1B60000u,  2u}, // wni -> Arab
     {0xD1B60000u, 46u}, // wnu -> Latn
     {0x776F0000u, 46u}, // wo -> Latn
     {0x85D60000u, 46u}, // wob -> Latn
     {0xC9D60000u, 46u}, // wos -> Latn
     {0xCA360000u, 46u}, // wrs -> Latn
-    {0x9A560000u, 22u}, // wsg -> Gong
+    {0x9A560000u, 23u}, // wsg -> Gong
     {0xAA560000u, 46u}, // wsk -> Latn
-    {0xB2760000u, 18u}, // wtm -> Deva
-    {0xD2960000u, 28u}, // wuu -> Hans
+    {0xB2760000u, 19u}, // wtm -> Deva
+    {0xD2960000u, 29u}, // wuu -> Hans
     {0xD6960000u, 46u}, // wuv -> Latn
     {0x82D60000u, 46u}, // wwa -> Latn
     {0xD4170000u, 46u}, // xav -> Latn
     {0xA0370000u, 46u}, // xbi -> Latn
-    {0xB8570000u, 14u}, // xco -> Chrs
-    {0xC4570000u, 11u}, // xcr -> Cari
+    {0xB8570000u, 15u}, // xco -> Chrs
+    {0xC4570000u, 12u}, // xcr -> Cari
     {0xC8970000u, 46u}, // xes -> Latn
     {0x78680000u, 46u}, // xh -> Latn
     {0x81770000u, 46u}, // xla -> Latn
     {0x89770000u, 50u}, // xlc -> Lyci
     {0x8D770000u, 51u}, // xld -> Lydi
-    {0x95970000u, 21u}, // xmf -> Geor
+    {0x95970000u, 22u}, // xmf -> Geor
     {0xB5970000u, 53u}, // xmn -> Mani
-    {0xC5970000u, 54u}, // xmr -> Merc
-    {0x81B70000u, 59u}, // xna -> Narb
-    {0xC5B70000u, 18u}, // xnr -> Deva
+    {0xC5970000u, 55u}, // xmr -> Merc
+    {0x81B70000u, 60u}, // xna -> Narb
+    {0xC5B70000u, 19u}, // xnr -> Deva
     {0x99D70000u, 46u}, // xog -> Latn
     {0xB5D70000u, 46u}, // xon -> Latn
-    {0xC5F70000u, 71u}, // xpr -> Prti
+    {0xC5F70000u, 72u}, // xpr -> Prti
     {0x86370000u, 46u}, // xrb -> Latn
-    {0x82570000u, 74u}, // xsa -> Sarb
+    {0x82570000u, 75u}, // xsa -> Sarb
     {0xA2570000u, 46u}, // xsi -> Latn
     {0xB2570000u, 46u}, // xsm -> Latn
-    {0xC6570000u, 18u}, // xsr -> Deva
+    {0xC6570000u, 19u}, // xsr -> Deva
     {0x92D70000u, 46u}, // xwe -> Latn
     {0xB0180000u, 46u}, // yam -> Latn
     {0xB8180000u, 46u}, // yao -> Latn
@@ -1458,33 +1460,33 @@
     {0xAE380000u, 46u}, // yrl -> Latn
     {0xCA580000u, 46u}, // yss -> Latn
     {0x82980000u, 46u}, // yua -> Latn
-    {0x92980000u, 29u}, // yue -> Hant
-    {0x9298434Eu, 28u}, // yue-CN -> Hans
+    {0x92980000u, 30u}, // yue -> Hant
+    {0x9298434Eu, 29u}, // yue-CN -> Hans
     {0xA6980000u, 46u}, // yuj -> Latn
     {0xCE980000u, 46u}, // yut -> Latn
     {0xDA980000u, 46u}, // yuw -> Latn
     {0x7A610000u, 46u}, // za -> Latn
     {0x98190000u, 46u}, // zag -> Latn
-    {0xA4790000u,  1u}, // zdj -> Arab
+    {0xA4790000u,  2u}, // zdj -> Arab
     {0x80990000u, 46u}, // zea -> Latn
-    {0x9CD90000u, 88u}, // zgh -> Tfng
-    {0x7A680000u, 28u}, // zh -> Hans
-    {0x7A684155u, 29u}, // zh-AU -> Hant
-    {0x7A68424Eu, 29u}, // zh-BN -> Hant
-    {0x7A684742u, 29u}, // zh-GB -> Hant
-    {0x7A684746u, 29u}, // zh-GF -> Hant
-    {0x7A68484Bu, 29u}, // zh-HK -> Hant
-    {0x7A684944u, 29u}, // zh-ID -> Hant
-    {0x7A684D4Fu, 29u}, // zh-MO -> Hant
-    {0x7A685041u, 29u}, // zh-PA -> Hant
-    {0x7A685046u, 29u}, // zh-PF -> Hant
-    {0x7A685048u, 29u}, // zh-PH -> Hant
-    {0x7A685352u, 29u}, // zh-SR -> Hant
-    {0x7A685448u, 29u}, // zh-TH -> Hant
-    {0x7A685457u, 29u}, // zh-TW -> Hant
-    {0x7A685553u, 29u}, // zh-US -> Hant
-    {0x7A68564Eu, 29u}, // zh-VN -> Hant
-    {0xDCF90000u, 61u}, // zhx -> Nshu
+    {0x9CD90000u, 89u}, // zgh -> Tfng
+    {0x7A680000u, 29u}, // zh -> Hans
+    {0x7A684155u, 30u}, // zh-AU -> Hant
+    {0x7A68424Eu, 30u}, // zh-BN -> Hant
+    {0x7A684742u, 30u}, // zh-GB -> Hant
+    {0x7A684746u, 30u}, // zh-GF -> Hant
+    {0x7A68484Bu, 30u}, // zh-HK -> Hant
+    {0x7A684944u, 30u}, // zh-ID -> Hant
+    {0x7A684D4Fu, 30u}, // zh-MO -> Hant
+    {0x7A685041u, 30u}, // zh-PA -> Hant
+    {0x7A685046u, 30u}, // zh-PF -> Hant
+    {0x7A685048u, 30u}, // zh-PH -> Hant
+    {0x7A685352u, 30u}, // zh-SR -> Hant
+    {0x7A685448u, 30u}, // zh-TH -> Hant
+    {0x7A685457u, 30u}, // zh-TW -> Hant
+    {0x7A685553u, 30u}, // zh-US -> Hant
+    {0x7A68564Eu, 30u}, // zh-VN -> Hant
+    {0xDCF90000u, 62u}, // zhx -> Nshu
     {0x81190000u, 46u}, // zia -> Latn
     {0xCD590000u, 41u}, // zkt -> Kits
     {0xB1790000u, 46u}, // zlm -> Latn
@@ -1642,6 +1644,7 @@
     0xB48343414C61746ELLU, // den_Latn_CA
     0xC4C343414C61746ELLU, // dgr_Latn_CA
     0x91234E454C61746ELLU, // dje_Latn_NE
+    0x95834E474D656466LLU, // dmf_Medf_NG
     0xA5A343494C61746ELLU, // dnj_Latn_CI
     0xA1C3494E44657661LLU, // doi_Deva_IN
     0x9E23434E4D6F6E67LLU, // drh_Mong_CN
@@ -1917,8 +1920,6 @@
     0x6D684D484C61746ELLU, // mh_Latn_MH
     0x6D694E5A4C61746ELLU, // mi_Latn_NZ
     0xB50C49444C61746ELLU, // min_Latn_ID
-    0xC90C495148617472LLU, // mis_Hatr_IQ
-    0xC90C4E474D656466LLU, // mis_Medf_NG
     0x6D6B4D4B4379726CLLU, // mk_Cyrl_MK
     0x6D6C494E4D6C796DLLU, // ml_Mlym_IN
     0xC96C53444C61746ELLU, // mls_Latn_SD
@@ -2174,6 +2175,7 @@
     0x747950464C61746ELLU, // ty_Latn_PF
     0xD71352554379726CLLU, // tyv_Cyrl_RU
     0xB3334D414C61746ELLU, // tzm_Latn_MA
+    0xA074525541676862LLU, // udi_Aghb_RU
     0xB07452554379726CLLU, // udm_Cyrl_RU
     0x7567434E41726162LLU, // ug_Arab_CN
     0x75674B5A4379726CLLU, // ug_Cyrl_KZ
@@ -2382,6 +2384,8 @@
     {0x65735553u, 0x6573A424u}, // es-US -> es-419
     {0x65735559u, 0x6573A424u}, // es-UY -> es-419
     {0x65735645u, 0x6573A424u}, // es-VE -> es-419
+    {0x6E620000u, 0x6E6F0000u}, // nb -> no
+    {0x6E6E0000u, 0x6E6F0000u}, // nn -> no
     {0x7074414Fu, 0x70745054u}, // pt-AO -> pt-PT
     {0x70744348u, 0x70745054u}, // pt-CH -> pt-PT
     {0x70744356u, 0x70745054u}, // pt-CV -> pt-PT
diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp
index 4ec525a..0269128 100644
--- a/libs/androidfw/PosixUtils.cpp
+++ b/libs/androidfw/PosixUtils.cpp
@@ -114,10 +114,10 @@
       std::unique_ptr<ProcResult> result(new ProcResult());
       result->status = status;
       const auto out = ReadFile(stdout[0]);
-      result->stdout = out ? *out : "";
+      result->stdout_str = out ? *out : "";
       close(stdout[0]);
       const auto err = ReadFile(stderr[0]);
-      result->stderr = err ? *err : "";
+      result->stderr_str = err ? *err : "";
       close(stderr[0]);
       return result;
   }
diff --git a/libs/androidfw/include/androidfw/PosixUtils.h b/libs/androidfw/include/androidfw/PosixUtils.h
index 8fc3ee2..bb20847 100644
--- a/libs/androidfw/include/androidfw/PosixUtils.h
+++ b/libs/androidfw/include/androidfw/PosixUtils.h
@@ -23,8 +23,8 @@
 
 struct ProcResult {
   int status;
-  std::string stdout;
-  std::string stderr;
+  std::string stdout_str;
+  std::string stderr_str;
 };
 
 // Fork, exec and wait for an external process. Return nullptr if the process could not be launched,
diff --git a/libs/androidfw/tests/PosixUtils_test.cpp b/libs/androidfw/tests/PosixUtils_test.cpp
index cf97f87..c7b3eba 100644
--- a/libs/androidfw/tests/PosixUtils_test.cpp
+++ b/libs/androidfw/tests/PosixUtils_test.cpp
@@ -30,14 +30,14 @@
   const auto result = ExecuteBinary({"/bin/date", "--help"});
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, 0);
-  ASSERT_EQ(result->stdout.find("usage: date "), 0);
+  ASSERT_EQ(result->stdout_str.find("usage: date "), 0);
 }
 
 TEST(PosixUtilsTest, RelativePathToBinary) {
   const auto result = ExecuteBinary({"date", "--help"});
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, 0);
-  ASSERT_EQ(result->stdout.find("usage: date "), 0);
+  ASSERT_EQ(result->stdout_str.find("usage: date "), 0);
 }
 
 TEST(PosixUtilsTest, BadParameters) {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 6cb53206..0b3b393 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -21,6 +21,7 @@
 // TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead.
 #include <surfacetexture/surface_texture_platform.h>
 #include "AutoBackendTextureRelease.h"
+#include "Matrix.h"
 #include "Properties.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/EglManager.h"
@@ -144,17 +145,18 @@
         }
         if (mUpdateTexImage) {
             mUpdateTexImage = false;
+            float transformMatrix[16];
             android_dataspace dataspace;
             int slot;
             bool newContent = false;
-            ARect rect;
-            uint32_t textureTransform;
+            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, &newContent, createReleaseFence,
-                    fenceWait, this, &rect, &textureTransform);
+                    mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &outTransform,
+                    &newContent, createReleaseFence, fenceWait, this, &currentCrop);
 
             if (hardwareBuffer) {
                 mCurrentSlot = slot;
@@ -168,9 +170,10 @@
                     // force filtration if buffer size != layer size
                     bool forceFilter =
                             mWidth != layerImage->width() || mHeight != layerImage->height();
-                    SkRect cropRect =
-                            SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
-                    updateLayer(forceFilter, textureTransform, cropRect, layerImage);
+                    SkRect currentCropRect =
+                            SkRect::MakeLTRB(currentCrop.left, currentCrop.top, currentCrop.right,
+                                             currentCrop.bottom);
+                    updateLayer(forceFilter, layerImage, outTransform, currentCropRect);
                 }
             }
         }
@@ -182,13 +185,13 @@
     }
 }
 
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const uint32_t textureTransform,
-                                       const SkRect cropRect, const sk_sp<SkImage>& layerImage) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const sk_sp<SkImage>& layerImage,
+                                       const uint32_t transform, SkRect currentCrop) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
-    mLayer->setTextureTransform(textureTransform);
-    mLayer->setCropRect(cropRect);
+    mLayer->setCurrentCropRect(currentCrop);
+    mLayer->setWindowTransform(transform);
     mLayer->setImage(layerImage);
 }
 
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 7a63ccd..da8041f 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -90,8 +90,8 @@
 
     void detachSurfaceTexture();
 
-    void updateLayer(bool forceFilter, const uint32_t textureTransform, const SkRect cropRect,
-                     const sk_sp<SkImage>& layerImage);
+    void updateLayer(bool forceFilter, const sk_sp<SkImage>& layerImage, const uint32_t transform,
+                     SkRect currentCrop);
 
     void destroyLayer();
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 656a817..0789344 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -76,15 +76,15 @@
 
     inline SkMatrix& getTransform() { return transform; }
 
-    inline SkRect getCropRect() { return mCropRect; }
+    inline SkRect getCurrentCropRect() { return mCurrentCropRect; }
 
-    inline void setCropRect(const SkRect cropRect) { mCropRect = cropRect; }
-
-    inline void setTextureTransform(uint32_t textureTransform) {
-        mTextureTransform = textureTransform;
+    inline void setCurrentCropRect(const SkRect currentCropRect) {
+        mCurrentCropRect = currentCropRect;
     }
 
-    inline uint32_t getTextureTransform() { return mTextureTransform; }
+    inline void setWindowTransform(uint32_t windowTransform) { mWindowTransform = windowTransform; }
+
+    inline uint32_t getWindowTransform() { return mWindowTransform; }
 
     /**
      * Posts a decStrong call to the appropriate thread.
@@ -131,12 +131,12 @@
     /**
      * Optional crop
      */
-    SkRect mCropRect;
+    SkRect mCurrentCropRect;
 
     /**
      * Optional transform
      */
-    uint32_t mTextureTransform;
+    uint32_t mWindowTransform;
 
     /**
      * An image backing the layer.
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index c804418..9cf300c 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -84,7 +84,7 @@
 bool Properties::useHintManager = true;
 int Properties::targetCpuTimePercentage = 70;
 
-bool Properties::enableWebViewOverlays = false;
+bool Properties::enableWebViewOverlays = true;
 
 StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI;
 
@@ -141,7 +141,7 @@
     targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70);
     if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70;
 
-    enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false);
+    enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, true);
 
     // call isDrawingEnabled to force loading of the property
     isDrawingEnabled();
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 386c88a..4cce87a 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -243,16 +243,14 @@
             static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
     sk_sp<SkImage> image =
             SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
-    return copyImageInto(image, texTransform, srcRect, bitmap);
+    return copyImageInto(image, srcRect, bitmap);
 }
 
 CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
     LOG_ALWAYS_FATAL_IF(!hwBitmap->isHardware());
 
     Rect srcRect;
-    Matrix4 transform;
-
-    return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap);
+    return copyImageInto(hwBitmap->makeImage(), srcRect, bitmap);
 }
 
 CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
@@ -277,12 +275,11 @@
 
 CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap) {
     Rect srcRect;
-    Matrix4 transform;
-    return copyImageInto(image, transform, srcRect, bitmap);
+    return copyImageInto(image, srcRect, bitmap);
 }
 
-CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
-                                   const Rect& srcRect, SkBitmap* bitmap) {
+CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, const Rect& srcRect,
+                                   SkBitmap* bitmap) {
     ATRACE_CALL();
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
         mRenderThread.requireGlContext();
@@ -299,11 +296,6 @@
     CopyResult copyResult = CopyResult::UnknownError;
 
     int displayedWidth = imgWidth, displayedHeight = imgHeight;
-    // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
-    // size.
-    if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) {
-        std::swap(displayedWidth, displayedHeight);
-    }
     SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
     SkRect skiaSrcRect = srcRect.toSkRect();
     if (skiaSrcRect.isEmpty()) {
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index da25269..d0d748f 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -56,8 +56,7 @@
 
 private:
     CopyResult copySurfaceIntoLegacy(ANativeWindow* window, const Rect& srcRect, SkBitmap* bitmap);
-    CopyResult copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
-                             const Rect& srcRect, SkBitmap* bitmap);
+    CopyResult copyImageInto(const sk_sp<SkImage>& image, const Rect& srcRect, SkBitmap* bitmap);
 
     bool copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect,
                        SkBitmap* bitmap);
diff --git a/libs/hwui/apex/android_matrix.cpp b/libs/hwui/apex/android_matrix.cpp
index 693b22b..04ac3cf 100644
--- a/libs/hwui/apex/android_matrix.cpp
+++ b/libs/hwui/apex/android_matrix.cpp
@@ -35,3 +35,10 @@
     }
     return false;
 }
+
+jobject AMatrix_newInstance(JNIEnv* env, float values[9]) {
+    jobject matrixObj = android::android_graphics_Matrix_newInstance(env);
+    SkMatrix* m = android::android_graphics_Matrix_getSkMatrix(env, matrixObj);
+    m->set9(values);
+    return matrixObj;
+}
diff --git a/libs/hwui/apex/include/android/graphics/matrix.h b/libs/hwui/apex/include/android/graphics/matrix.h
index 987ad13..5705ba4 100644
--- a/libs/hwui/apex/include/android/graphics/matrix.h
+++ b/libs/hwui/apex/include/android/graphics/matrix.h
@@ -34,6 +34,16 @@
  */
 ANDROID_API bool AMatrix_getContents(JNIEnv* env, jobject matrixObj, float values[9]);
 
+/**
+ * Returns a new Matrix jobject that contains the values passed in as initial values.
+ * @param values The 9 values of the 3x3 matrix in the following order.
+ *               values[0] = scaleX  values[1] = skewX   values[2] = transX
+ *               values[3] = skewY   values[4] = scaleY  values[5] = transY
+ *               values[6] = persp0  values[7] = persp1  values[8] = persp2
+ * @return The matrix jobject
+ */
+ANDROID_API jobject AMatrix_newInstance(JNIEnv* env, float values[9]);
+
 __END_DECLS
 
 #endif // ANDROID_GRAPHICS_MATRIX_H
diff --git a/libs/hwui/canvas/CanvasFrontend.cpp b/libs/hwui/canvas/CanvasFrontend.cpp
index dd01a5b..112ac12 100644
--- a/libs/hwui/canvas/CanvasFrontend.cpp
+++ b/libs/hwui/canvas/CanvasFrontend.cpp
@@ -30,41 +30,61 @@
     mClipStack.clear();
     mTransformStack.clear();
     mSaveStack.emplace_back();
-    mClipStack.emplace_back().setRect(mInitialBounds);
+    mClipStack.emplace_back();
     mTransformStack.emplace_back();
-    mCurrentClipIndex = 0;
-    mCurrentTransformIndex = 0;
+
+    clip().bounds = mInitialBounds;
 }
 
 bool CanvasStateHelper::internalSave(SaveEntry saveEntry) {
     mSaveStack.push_back(saveEntry);
     if (saveEntry.matrix) {
-        // We need to push before accessing transform() to ensure the reference doesn't move
-        // across vector resizes
-        mTransformStack.emplace_back() = transform();
-        mCurrentTransformIndex += 1;
+        pushEntry(&mTransformStack);
     }
     if (saveEntry.clip) {
-        // We need to push before accessing clip() to ensure the reference doesn't move
-        // across vector resizes
-        mClipStack.emplace_back() = clip();
-        mCurrentClipIndex += 1;
+        pushEntry(&mClipStack);
         return true;
     }
     return false;
 }
 
-// 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);
+void CanvasStateHelper::ConservativeClip::apply(SkClipOp op, const SkMatrix& matrix,
+                                                const SkRect& bounds, bool aa, bool fillsBounds) {
+    this->aa |= aa;
+
+    if (op == SkClipOp::kIntersect) {
+        SkRect devBounds;
+        bool rect = matrix.mapRect(&devBounds, bounds) && fillsBounds;
+        if (!this->bounds.intersect(aa ? devBounds.roundOut() : devBounds.round())) {
+            this->bounds.setEmpty();
+        }
+        this->rect &= rect;
+    } else {
+        // Difference operations subtracts a region from the clip, so conservatively
+        // the bounds remain unchanged and the shape is unlikely to remain a rect.
+        this->rect = false;
+    }
+}
 
 void CanvasStateHelper::internalClipRect(const SkRect& rect, SkClipOp op) {
-    clip().opRect(rect, transform(), mInitialBounds, (SkRegion::Op)op, false);
+    clip().apply(op, transform(), rect, /*aa=*/false, /*fillsBounds=*/true);
 }
 
 void CanvasStateHelper::internalClipPath(const SkPath& path, SkClipOp op) {
-    clip().opPath(path, transform(), mInitialBounds, (SkRegion::Op)op, true);
+    SkRect bounds = path.getBounds();
+    if (path.isInverseFillType()) {
+        // Toggle op type if the path is inverse filled
+        op = (op == SkClipOp::kIntersect ? SkClipOp::kDifference : SkClipOp::kIntersect);
+    }
+    clip().apply(op, transform(), bounds, /*aa=*/true, /*fillsBounds=*/false);
+}
+
+CanvasStateHelper::ConservativeClip& CanvasStateHelper::clip() {
+    return writableEntry(&mClipStack);
+}
+
+SkMatrix& CanvasStateHelper::transform() {
+    return writableEntry(&mTransformStack);
 }
 
 bool CanvasStateHelper::internalRestore() {
@@ -77,45 +97,47 @@
     mSaveStack.pop_back();
     bool needsRestorePropagation = entry.layer;
     if (entry.matrix) {
-        mTransformStack.pop_back();
-        mCurrentTransformIndex -= 1;
+        popEntry(&mTransformStack);
     }
     if (entry.clip) {
-        // We need to push before accessing clip() to ensure the reference doesn't move
-        // across vector resizes
-        mClipStack.pop_back();
-        mCurrentClipIndex -= 1;
+        popEntry(&mClipStack);
         needsRestorePropagation = true;
     }
     return needsRestorePropagation;
 }
 
 SkRect CanvasStateHelper::getClipBounds() const {
-    SkIRect ibounds = clip().getBounds();
-
-    if (ibounds.isEmpty()) {
-        return SkRect::MakeEmpty();
-    }
+    SkIRect bounds = clip().bounds;
 
     SkMatrix inverse;
     // if we can't invert the CTM, we can't return local clip bounds
-    if (!transform().invert(&inverse)) {
+    if (bounds.isEmpty() || !transform().invert(&inverse)) {
         return SkRect::MakeEmpty();
     }
 
-    SkRect ret = SkRect::MakeEmpty();
-    inverse.mapRect(&ret, SkRect::Make(ibounds));
-    return ret;
+    return inverse.mapRect(SkRect::Make(bounds));
+}
+
+bool CanvasStateHelper::ConservativeClip::quickReject(const SkMatrix& matrix,
+                                                      const SkRect& bounds) const {
+    SkRect devRect = matrix.mapRect(bounds);
+    return devRect.isFinite() &&
+           SkIRect::Intersects(this->bounds, aa ? devRect.roundOut() : devRect.round());
 }
 
 bool CanvasStateHelper::quickRejectRect(float left, float top, float right, float bottom) const {
-    // TODO: Implement
-    return false;
+    return clip().quickReject(transform(), SkRect::MakeLTRB(left, top, right, bottom));
 }
 
 bool CanvasStateHelper::quickRejectPath(const SkPath& path) const {
-    // TODO: Implement
-    return false;
+    if (this->isClipEmpty()) {
+        // reject everything (prioritized above path inverse fill type).
+        return true;
+    } else {
+        // Don't reject inverse-filled paths, since even if they are "empty" of points/verbs,
+        // they fill out the entire clip.
+        return !path.isInverseFillType() && clip().quickReject(transform(), path.getBounds());
+    }
 }
 
 } // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasFrontend.h b/libs/hwui/canvas/CanvasFrontend.h
index f9a6101..9f22b90 100644
--- a/libs/hwui/canvas/CanvasFrontend.h
+++ b/libs/hwui/canvas/CanvasFrontend.h
@@ -21,7 +21,6 @@
 #include "CanvasOpBuffer.h"
 #include <SaveFlags.h>
 
-#include <SkRasterClip.h>
 #include <ui/FatVector.h>
 
 #include <optional>
@@ -40,6 +39,26 @@
         bool layer : 1 = false;
     };
 
+    template <typename T>
+    struct DeferredEntry {
+        T entry;
+        int deferredSaveCount = 0;
+
+        DeferredEntry() = default;
+        DeferredEntry(const T& t) : entry(t) {}
+    };
+
+    struct ConservativeClip {
+        SkIRect bounds = SkIRect::MakeEmpty();
+        bool rect = true;
+        bool aa = false;
+
+        bool quickReject(const SkMatrix& matrix, const SkRect& bounds) const;
+
+        void apply(SkClipOp op, const SkMatrix& matrix, const SkRect& bounds, bool aa,
+                   bool fillsBounds);
+    };
+
     constexpr SaveEntry saveEntryForLayer() {
         return {
             .clip = true,
@@ -72,24 +91,48 @@
     void internalClipRect(const SkRect& rect, SkClipOp op);
     void internalClipPath(const SkPath& path, SkClipOp op);
 
+    // The canvas' clip will never expand beyond these bounds since intersect
+    // and difference operations only subtract pixels.
     SkIRect mInitialBounds;
+    // Every save() gets a SaveEntry to track what needs to be restored.
     FatVector<SaveEntry, 6> mSaveStack;
-    FatVector<SkMatrix, 6> mTransformStack;
-    FatVector<SkConservativeClip, 6> mClipStack;
+    // Transform and clip entries record a deferred save count and do not
+    // make a new entry until that particular state is modified.
+    FatVector<DeferredEntry<SkMatrix>, 6> mTransformStack;
+    FatVector<DeferredEntry<ConservativeClip>, 6> mClipStack;
 
-    size_t mCurrentTransformIndex;
-    size_t mCurrentClipIndex;
+    const ConservativeClip& clip() const { return mClipStack.back().entry; }
 
-    const SkConservativeClip& clip() const {
-        return mClipStack[mCurrentClipIndex];
-    }
-
-    SkConservativeClip& clip() {
-        return mClipStack[mCurrentClipIndex];
-    }
+    ConservativeClip& clip();
 
     void resetState(int width, int height);
 
+    // Stack manipulation for transform and clip stacks
+    template <typename T, size_t N>
+    void pushEntry(FatVector<DeferredEntry<T>, N>* stack) {
+        stack->back().deferredSaveCount += 1;
+    }
+
+    template <typename T, size_t N>
+    void popEntry(FatVector<DeferredEntry<T>, N>* stack) {
+        if (!(stack->back().deferredSaveCount--)) {
+            stack->pop_back();
+        }
+    }
+
+    template <typename T, size_t N>
+    T& writableEntry(FatVector<DeferredEntry<T>, N>* stack) {
+        DeferredEntry<T>& back = stack->back();
+        if (back.deferredSaveCount == 0) {
+            return back.entry;
+        } else {
+            back.deferredSaveCount -= 1;
+            // saved in case references move when re-allocating vector storage
+            T state = back.entry;
+            return stack->emplace_back(state).entry;
+        }
+    }
+
 public:
     int saveCount() const { return mSaveStack.size(); }
 
@@ -97,13 +140,14 @@
     bool quickRejectRect(float left, float top, float right, float bottom) const;
     bool quickRejectPath(const SkPath& path) const;
 
-    const SkMatrix& transform() const {
-        return mTransformStack[mCurrentTransformIndex];
-    }
+    bool isClipAA() const { return clip().aa; }
+    bool isClipEmpty() const { return clip().bounds.isEmpty(); }
+    bool isClipRect() const { return clip().rect; }
+    bool isClipComplex() const { return !isClipEmpty() && (isClipAA() || !isClipRect()); }
 
-    SkMatrix& transform() {
-        return mTransformStack[mCurrentTransformIndex];
-    }
+    const SkMatrix& transform() const { return mTransformStack.back().entry; }
+
+    SkMatrix& transform();
 
     // For compat with existing HWUI Canvas interface
     void getMatrix(SkMatrix* outMatrix) const {
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index db59154..e536950 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -73,6 +73,10 @@
 } gFrameDrawingCallback;
 
 struct {
+    jmethodID onFrameCommit;
+} gFrameCommitCallback;
+
+struct {
     jmethodID onFrameComplete;
 } gFrameCompleteCallback;
 
@@ -101,22 +105,21 @@
     JavaVM* mVm;
 };
 
-class FrameCompleteWrapper : public LightRefBase<FrameCompleteWrapper> {
+class FrameCommitWrapper : public LightRefBase<FrameCommitWrapper> {
 public:
-    explicit FrameCompleteWrapper(JNIEnv* env, jobject jobject) {
+    explicit FrameCommitWrapper(JNIEnv* env, jobject jobject) {
         env->GetJavaVM(&mVm);
         mObject = env->NewGlobalRef(jobject);
         LOG_ALWAYS_FATAL_IF(!mObject, "Failed to make global ref");
     }
 
-    ~FrameCompleteWrapper() {
-        releaseObject();
-    }
+    ~FrameCommitWrapper() { releaseObject(); }
 
-    void onFrameComplete(int64_t frameNr) {
+    void onFrameCommit(bool didProduceBuffer) {
         if (mObject) {
-            ATRACE_FORMAT("frameComplete %" PRId64, frameNr);
-            getenv(mVm)->CallVoidMethod(mObject, gFrameCompleteCallback.onFrameComplete, frameNr);
+            ATRACE_FORMAT("frameCommit success=%d", didProduceBuffer);
+            getenv(mVm)->CallVoidMethod(mObject, gFrameCommitCallback.onFrameCommit,
+                                        didProduceBuffer);
             releaseObject();
         }
     }
@@ -423,28 +426,6 @@
     jobject mObject;
 };
 
-class JWeakGlobalRefHolder {
-public:
-    JWeakGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm) {
-        mWeakRef = getenv(vm)->NewWeakGlobalRef(object);
-    }
-
-    virtual ~JWeakGlobalRefHolder() {
-        if (mWeakRef != nullptr) getenv(mVm)->DeleteWeakGlobalRef(mWeakRef);
-        mWeakRef = nullptr;
-    }
-
-    jobject ref() { return mWeakRef; }
-    JavaVM* vm() { return mVm; }
-
-private:
-    JWeakGlobalRefHolder(const JWeakGlobalRefHolder&) = delete;
-    void operator=(const JWeakGlobalRefHolder&) = delete;
-
-    JavaVM* mVm;
-    jobject mWeakRef;
-};
-
 using TextureMap = std::unordered_map<uint32_t, sk_sp<SkImage>>;
 
 struct PictureCaptureState {
@@ -578,20 +559,16 @@
     } else {
         JavaVM* vm = nullptr;
         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
-        auto globalCallbackRef =
-                std::make_shared<JWeakGlobalRefHolder>(vm, aSurfaceTransactionCallback);
+        auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(
+                vm, env->NewGlobalRef(aSurfaceTransactionCallback));
         proxy->setASurfaceTransactionCallback(
                 [globalCallbackRef](int64_t transObj, int64_t scObj, int64_t frameNr) -> bool {
                     JNIEnv* env = getenv(globalCallbackRef->vm());
-                    jobject localref = env->NewLocalRef(globalCallbackRef->ref());
-                    if (CC_UNLIKELY(!localref)) {
-                        return false;
-                    }
                     jboolean ret = env->CallBooleanMethod(
-                            localref, gASurfaceTransactionCallback.onMergeTransaction,
+                            globalCallbackRef->object(),
+                            gASurfaceTransactionCallback.onMergeTransaction,
                             static_cast<jlong>(transObj), static_cast<jlong>(scObj),
                             static_cast<jlong>(frameNr));
-                    env->DeleteLocalRef(localref);
                     return ret;
                 });
     }
@@ -606,15 +583,11 @@
         JavaVM* vm = nullptr;
         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
         auto globalCallbackRef =
-                std::make_shared<JWeakGlobalRefHolder>(vm, callback);
+                std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback));
         proxy->setPrepareSurfaceControlForWebviewCallback([globalCallbackRef]() {
             JNIEnv* env = getenv(globalCallbackRef->vm());
-            jobject localref = env->NewLocalRef(globalCallbackRef->ref());
-            if (CC_UNLIKELY(!localref)) {
-                return;
-            }
-            env->CallVoidMethod(localref, gPrepareSurfaceControlForWebviewCallback.prepare);
-            env->DeleteLocalRef(localref);
+            env->CallVoidMethod(globalCallbackRef->object(),
+                                gPrepareSurfaceControlForWebviewCallback.prepare);
         });
     }
 }
@@ -637,15 +610,33 @@
     }
 }
 
+static void android_view_ThreadedRenderer_setFrameCommitCallback(JNIEnv* env, jobject clazz,
+                                                                 jlong proxyPtr, jobject callback) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    if (!callback) {
+        proxy->setFrameCommitCallback(nullptr);
+    } else {
+        sp<FrameCommitWrapper> wrapper = new FrameCommitWrapper{env, callback};
+        proxy->setFrameCommitCallback(
+                [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); });
+    }
+}
+
 static void android_view_ThreadedRenderer_setFrameCompleteCallback(JNIEnv* env,
         jobject clazz, jlong proxyPtr, jobject callback) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     if (!callback) {
         proxy->setFrameCompleteCallback(nullptr);
     } else {
-        sp<FrameCompleteWrapper> wrapper = new FrameCompleteWrapper{env, callback};
-        proxy->setFrameCompleteCallback([wrapper](int64_t frameNr) {
-            wrapper->onFrameComplete(frameNr);
+        RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+        JavaVM* vm = nullptr;
+        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+        auto globalCallbackRef =
+                std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback));
+        proxy->setFrameCompleteCallback([globalCallbackRef]() {
+            JNIEnv* env = getenv(globalCallbackRef->vm());
+            env->CallVoidMethod(globalCallbackRef->object(),
+                                gFrameCompleteCallback.onFrameComplete);
         });
     }
 }
@@ -937,6 +928,8 @@
          (void*)android_view_ThreadedRenderer_setPrepareSurfaceControlForWebviewCallback},
         {"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
          (void*)android_view_ThreadedRenderer_setFrameCallback},
+        {"nSetFrameCommitCallback", "(JLandroid/graphics/HardwareRenderer$FrameCommitCallback;)V",
+         (void*)android_view_ThreadedRenderer_setFrameCommitCallback},
         {"nSetFrameCompleteCallback",
          "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
          (void*)android_view_ThreadedRenderer_setFrameCompleteCallback},
@@ -1004,10 +997,15 @@
     gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
             "onFrameDraw", "(J)V");
 
+    jclass frameCommitClass =
+            FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameCommitCallback");
+    gFrameCommitCallback.onFrameCommit =
+            GetMethodIDOrDie(env, frameCommitClass, "onFrameCommit", "(Z)V");
+
     jclass frameCompleteClass = FindClassOrDie(env,
             "android/graphics/HardwareRenderer$FrameCompleteCallback");
-    gFrameCompleteCallback.onFrameComplete = GetMethodIDOrDie(env, frameCompleteClass,
-            "onFrameComplete", "(J)V");
+    gFrameCompleteCallback.onFrameComplete =
+            GetMethodIDOrDie(env, frameCompleteClass, "onFrameComplete", "()V");
 
     void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
     fromSurface = (ANW_fromSurface)dlsym(handle_, "ANativeWindow_fromSurface");
diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
index e5d5e75..6cae5ff 100644
--- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
@@ -24,6 +24,7 @@
 namespace android {
 
 struct {
+    jclass clazz;
     jmethodID callback;
 } gHardwareRendererObserverClassInfo;
 
@@ -38,14 +39,13 @@
 HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer,
                                                    bool waitForPresentTime)
         : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) {
-    mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer);
-    LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
-            "unable to create frame stats observer reference");
+    mObserver = getenv(mVm)->NewGlobalRef(observer);
+    LOG_ALWAYS_FATAL_IF(mObserver == nullptr, "unable to create frame stats observer reference");
 }
 
 HardwareRendererObserver::~HardwareRendererObserver() {
     JNIEnv* env = getenv(mVm);
-    env->DeleteWeakGlobalRef(mObserverWeak);
+    env->DeleteGlobalRef(mObserver);
 }
 
 bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) {
@@ -66,6 +66,8 @@
 }
 
 void HardwareRendererObserver::notify(const int64_t* stats) {
+    if (!mKeepListening) return;
+
     FrameMetricsNotification& elem = mRingBuffer[mNextFree];
 
     if (!elem.hasData.load()) {
@@ -77,18 +79,17 @@
         elem.hasData = true;
 
         JNIEnv* env = getenv(mVm);
-        jobject target = env->NewLocalRef(mObserverWeak);
-        if (target != nullptr) {
-            env->CallVoidMethod(target, gHardwareRendererObserverClassInfo.callback);
-            env->DeleteLocalRef(target);
-        }
+        mKeepListening = env->CallStaticBooleanMethod(gHardwareRendererObserverClassInfo.clazz,
+                                                      gHardwareRendererObserverClassInfo.callback,
+                                                      mObserver);
     } else {
         mDroppedReports++;
     }
 }
 
 static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env,
-                                                                      jobject observerObj,
+                                                                      jobject /*clazz*/,
+                                                                      jobject weakRefThis,
                                                                       jboolean waitForPresentTime) {
     JavaVM* vm = nullptr;
     if (env->GetJavaVM(&vm) != JNI_OK) {
@@ -97,7 +98,7 @@
     }
 
     HardwareRendererObserver* observer =
-            new HardwareRendererObserver(vm, observerObj, waitForPresentTime);
+            new HardwareRendererObserver(vm, weakRefThis, waitForPresentTime);
     return reinterpret_cast<jlong>(observer);
 }
 
@@ -114,7 +115,7 @@
 }
 
 static const std::array gMethods = {
-        MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Z)J",
+        MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Ljava/lang/ref/WeakReference;Z)J",
                                android_graphics_HardwareRendererObserver_createObserver),
         MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
                                android_graphics_HardwareRendererObserver_getNextBuffer),
@@ -123,8 +124,10 @@
 int register_android_graphics_HardwareRendererObserver(JNIEnv* env) {
 
     jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver");
-    gHardwareRendererObserverClassInfo.callback = GetMethodIDOrDie(env, observerClass,
-                                                                   "notifyDataAvailable", "()V");
+    gHardwareRendererObserverClassInfo.clazz =
+            reinterpret_cast<jclass>(env->NewGlobalRef(observerClass));
+    gHardwareRendererObserverClassInfo.callback = GetStaticMethodIDOrDie(
+            env, observerClass, "invokeDataAvailable", "(Ljava/lang/ref/WeakReference;)Z");
 
     return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver",
                                 gMethods.data(), gMethods.size());
diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
index d307614..5ee3e16 100644
--- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
@@ -63,7 +63,8 @@
     };
 
     JavaVM* const mVm;
-    jweak mObserverWeak;
+    jobject mObserver;
+    bool mKeepListening = true;
 
     int mNextFree = 0;
     int mNextInQueue = 0;
diff --git a/libs/hwui/jni/android_graphics_Matrix.cpp b/libs/hwui/jni/android_graphics_Matrix.cpp
index 7338ef2..cf6702e 100644
--- a/libs/hwui/jni/android_graphics_Matrix.cpp
+++ b/libs/hwui/jni/android_graphics_Matrix.cpp
@@ -378,13 +378,17 @@
     {"nEquals", "(JJ)Z", (void*) SkMatrixGlue::equals}
 };
 
+static jclass sClazz;
 static jfieldID sNativeInstanceField;
+static jmethodID sCtor;
 
 int register_android_graphics_Matrix(JNIEnv* env) {
     int result = RegisterMethodsOrDie(env, "android/graphics/Matrix", methods, NELEM(methods));
 
     jclass clazz = FindClassOrDie(env, "android/graphics/Matrix");
+    sClazz = MakeGlobalRefOrDie(env, clazz);
     sNativeInstanceField = GetFieldIDOrDie(env, clazz, "native_instance", "J");
+    sCtor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
 
     return result;
 }
@@ -393,4 +397,7 @@
     return reinterpret_cast<SkMatrix*>(env->GetLongField(matrixObj, sNativeInstanceField));
 }
 
+jobject android_graphics_Matrix_newInstance(JNIEnv* env) {
+    return env->NewObject(sClazz, sCtor);
+}
 }
diff --git a/libs/hwui/jni/android_graphics_Matrix.h b/libs/hwui/jni/android_graphics_Matrix.h
index fe90d2e..79de48b 100644
--- a/libs/hwui/jni/android_graphics_Matrix.h
+++ b/libs/hwui/jni/android_graphics_Matrix.h
@@ -25,6 +25,9 @@
 /* Gets the underlying SkMatrix from a Matrix object. */
 SkMatrix* android_graphics_Matrix_getSkMatrix(JNIEnv* env, jobject matrixObj);
 
+/* Creates a new Matrix java object. */
+jobject android_graphics_Matrix_newInstance(JNIEnv* env);
+
 } // namespace android
 
 #endif // _ANDROID_GRAPHICS_MATRIX_H_
diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt
index 73de0d1..77b8a44 100644
--- a/libs/hwui/libhwui.map.txt
+++ b/libs/hwui/libhwui.map.txt
@@ -28,6 +28,7 @@
     register_android_graphics_GraphicsStatsService;
     zygote_preload_graphics;
     AMatrix_getContents;
+    AMatrix_newInstance;
     APaint_createPaint;
     APaint_destroyPaint;
     APaint_setBlendMode;
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index b28277c..1439656 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -18,7 +18,6 @@
 #include <utils/MathUtils.h>
 
 #include "GrBackendSurface.h"
-#include "Matrix.h"
 #include "SkColorFilter.h"
 #include "SkSurface.h"
 #include "gl/GrGLTypes.h"
@@ -31,7 +30,7 @@
 void LayerDrawable::onDraw(SkCanvas* canvas) {
     Layer* layer = mLayerUpdater->backingLayer();
     if (layer) {
-        SkRect srcRect = layer->getCropRect();
+        SkRect srcRect = layer->getCurrentCropRect();
         DrawLayer(canvas->recordingContext(), canvas, layer, &srcRect, nullptr, true);
     }
 }
@@ -82,86 +81,84 @@
         return false;
     }
     // transform the matrix based on the layer
-    const uint32_t transform = layer->getTextureTransform();
+    // SkMatrix layerTransform = layer->getTransform();
+    const uint32_t windowTransform = layer->getWindowTransform();
     sk_sp<SkImage> layerImage = layer->getImage();
     const int layerWidth = layer->getWidth();
     const int layerHeight = layer->getHeight();
-    SkMatrix layerTransform = layer->getTransform();
+
     if (layerImage) {
-        SkMatrix matrix;
+        const int imageWidth = layerImage->width();
+        const int imageHeight = layerImage->height();
+
         if (useLayerTransform) {
-            matrix = layerTransform;
+            canvas->save();
+            canvas->concat(layer->getTransform());
         }
+
         SkPaint paint;
         paint.setAlpha(layer->getAlpha());
         paint.setBlendMode(layer->getMode());
         paint.setColorFilter(layer->getColorFilter());
-        const bool nonIdentityMatrix = !matrix.isIdentity();
-        if (nonIdentityMatrix) {
-            canvas->save();
-            canvas->concat(matrix);
-        }
-        const SkMatrix totalMatrix = canvas->getTotalMatrix();
-        if (dstRect || srcRect) {
-            SkMatrix matrixInv;
-            if (!matrix.invert(&matrixInv)) {
-                matrixInv = matrix;
-            }
-            SkRect skiaSrcRect;
-            if (srcRect && !srcRect->isEmpty()) {
-                skiaSrcRect = *srcRect;
-            } else {
-                skiaSrcRect = (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
-                                      ? SkRect::MakeIWH(layerHeight, layerWidth)
-                                      : SkRect::MakeIWH(layerWidth, layerHeight);
-            }
-            matrixInv.mapRect(&skiaSrcRect);
-            SkRect skiaDestRect;
-            if (dstRect && !dstRect->isEmpty()) {
-                skiaDestRect = *dstRect;
-            } else {
-                skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight);
-            }
-            matrixInv.mapRect(&skiaDestRect);
-            SkSamplingOptions sampling(SkFilterMode::kNearest);
-            if (layer->getForceFilter() ||
-                shouldFilterRect(totalMatrix, skiaSrcRect, skiaDestRect)) {
-                sampling = SkSamplingOptions(SkFilterMode::kLinear);
-            }
-
-            const float px = skiaDestRect.centerX();
-            const float py = skiaDestRect.centerY();
-            if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-                matrix.postScale(-1.f, 1.f, px, py);
-            }
-            if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-                matrix.postScale(1.f, -1.f, px, py);
-            }
-            if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-                matrix.postRotate(90, 0, 0);
-                matrix.postTranslate(skiaDestRect.height(), 0);
-            }
-            auto constraint = SkCanvas::kFast_SrcRectConstraint;
-            if (srcRect && srcRect->isEmpty()) {
-                constraint = SkCanvas::kStrict_SrcRectConstraint;
-            }
-            matrix.postConcat(SkMatrix::MakeRectToRect(skiaSrcRect, skiaDestRect,
-                                                       SkMatrix::kFill_ScaleToFit));
-            canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
-                                  constraint);
+        const SkMatrix& totalMatrix = canvas->getTotalMatrix();
+        SkRect skiaSrcRect;
+        if (srcRect && !srcRect->isEmpty()) {
+            skiaSrcRect = *srcRect;
         } else {
-            SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height());
-            SkSamplingOptions sampling(SkFilterMode::kNearest);
-            if (layer->getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) {
-                sampling = SkSamplingOptions(SkFilterMode::kLinear);
-            }
-            canvas->drawImage(layerImage.get(), 0, 0, sampling, &paint);
+            skiaSrcRect = SkRect::MakeIWH(imageWidth, imageHeight);
         }
+        SkRect skiaDestRect;
+        if (dstRect && !dstRect->isEmpty()) {
+            skiaDestRect = (windowTransform & NATIVE_WINDOW_TRANSFORM_ROT_90)
+                                   ? SkRect::MakeIWH(dstRect->height(), dstRect->width())
+                                   : SkRect::MakeIWH(dstRect->width(), dstRect->height());
+        } else {
+            skiaDestRect = (windowTransform & NATIVE_WINDOW_TRANSFORM_ROT_90)
+                                   ? SkRect::MakeIWH(layerHeight, layerWidth)
+                                   : SkRect::MakeIWH(layerWidth, layerHeight);
+        }
+
+        const float px = skiaDestRect.centerX();
+        const float py = skiaDestRect.centerY();
+        SkMatrix m;
+        if (windowTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+            m.postScale(-1.f, 1.f, px, py);
+        }
+        if (windowTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+            m.postScale(1.f, -1.f, px, py);
+        }
+        if (windowTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+            m.postRotate(90, 0, 0);
+            m.postTranslate(skiaDestRect.height(), 0);
+        }
+        auto constraint = SkCanvas::kFast_SrcRectConstraint;
+        if (srcRect && !srcRect->isEmpty()) {
+            constraint = SkCanvas::kStrict_SrcRectConstraint;
+        }
+
+        canvas->save();
+        canvas->concat(m);
+
+        // If (matrix is a rect-to-rect transform)
+        // and (src/dst buffers size match in screen coordinates)
+        // and (src/dst corners align fractionally),
+        // then use nearest neighbor, otherwise use bilerp sampling.
+        // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works
+        // only for SrcOver blending and without color filter (readback uses Src blending).
+        SkSamplingOptions sampling(SkFilterMode::kNearest);
+        if (layer->getForceFilter() || shouldFilterRect(totalMatrix, skiaSrcRect, skiaDestRect)) {
+            sampling = SkSamplingOptions(SkFilterMode::kLinear);
+        }
+
+        canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
+                              constraint);
+        canvas->restore();
         // restore the original matrix
-        if (nonIdentityMatrix) {
+        if (useLayerTransform) {
             canvas->restore();
         }
     }
+
     return layerImage != nullptr;
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ab9d0b2..0cd6ffb 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -483,13 +483,19 @@
     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();
-        for (auto& func : mFrameCompleteCallbacks) {
-            std::invoke(func, mFrameNumber);
+        for (auto& func : mFrameCommitCallbacks) {
+            std::invoke(func, false /* didProduceBuffer */);
         }
-        mFrameCompleteCallbacks.clear();
+        mFrameCommitCallbacks.clear();
         return 0;
     }
 
@@ -598,10 +604,10 @@
 #endif
 
     if (didSwap) {
-        for (auto& func : mFrameCompleteCallbacks) {
-            std::invoke(func, frameCompleteNr);
+        for (auto& func : mFrameCommitCallbacks) {
+            std::invoke(func, true /* didProduceBuffer */);
         }
-        mFrameCompleteCallbacks.clear();
+        mFrameCommitCallbacks.clear();
     }
 
     if (requireSwap) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2fed468..ed4a620 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -195,8 +195,8 @@
 
     IRenderPipeline* getRenderPipeline() { return mRenderPipeline.get(); }
 
-    void addFrameCompleteListener(std::function<void(int64_t)>&& func) {
-        mFrameCompleteCallbacks.push_back(std::move(func));
+    void addFrameCommitListener(std::function<void(bool)>&& func) {
+        mFrameCommitCallbacks.push_back(std::move(func));
     }
 
     void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback) {
@@ -328,7 +328,7 @@
     std::vector<std::future<void>> mFrameFences;
     std::unique_ptr<IRenderPipeline> mRenderPipeline;
 
-    std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks;
+    std::vector<std::function<void(bool)>> mFrameCommitCallbacks;
 
     // If set to true, we expect that callbacks into onSurfaceStatsAvailable
     bool mExpectSurfaceStats = false;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index e7081df..94aedd0 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -150,16 +150,18 @@
         canUnblockUiThread = syncFrameState(info);
         canDrawThisFrame = info.out.canDrawThisFrame;
 
-        if (mFrameCompleteCallback) {
-            mContext->addFrameCompleteListener(std::move(mFrameCompleteCallback));
-            mFrameCompleteCallback = nullptr;
+        if (mFrameCommitCallback) {
+            mContext->addFrameCommitListener(std::move(mFrameCommitCallback));
+            mFrameCommitCallback = nullptr;
         }
     }
 
     // Grab a copy of everything we need
     CanvasContext* context = mContext;
-    std::function<void(int64_t)> callback = std::move(mFrameCallback);
+    std::function<void(int64_t)> frameCallback = std::move(mFrameCallback);
+    std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
     mFrameCallback = nullptr;
+    mFrameCompleteCallback = nullptr;
     int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
     int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
     int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)];
@@ -170,9 +172,9 @@
     }
 
     // Even if we aren't drawing this vsync pulse the next frame number will still be accurate
-    if (CC_UNLIKELY(callback)) {
+    if (CC_UNLIKELY(frameCallback)) {
         context->enqueueFrameWork(
-                [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
+                [frameCallback, frameNr = context->getFrameNumber()]() { frameCallback(frameNr); });
     }
 
     nsecs_t dequeueBufferDuration = 0;
@@ -189,6 +191,10 @@
         context->waitOnFences();
     }
 
+    if (CC_UNLIKELY(frameCompleteCallback)) {
+        std::invoke(frameCompleteCallback);
+    }
+
     if (!canUnblockUiThread) {
         unblockUiThread();
     }
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 6a61a2b..e3ea802 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -81,7 +81,11 @@
         mFrameCallback = std::move(callback);
     }
 
-    void setFrameCompleteCallback(std::function<void(int64_t)>&& callback) {
+    void setFrameCommitCallback(std::function<void(bool)>&& callback) {
+        mFrameCommitCallback = std::move(callback);
+    }
+
+    void setFrameCompleteCallback(std::function<void()>&& callback) {
         mFrameCompleteCallback = std::move(callback);
     }
 
@@ -123,7 +127,8 @@
     int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
 
     std::function<void(int64_t)> mFrameCallback;
-    std::function<void(int64_t)> mFrameCompleteCallback;
+    std::function<void(bool)> mFrameCommitCallback;
+    std::function<void()> mFrameCompleteCallback;
 
     nsecs_t mLastDequeueBufferDuration = 0;
     nsecs_t mLastTargetWorkDuration = 0;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index c485ce2..72d4ac5 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -326,7 +326,11 @@
     mDrawFrameTask.setFrameCallback(std::move(callback));
 }
 
-void RenderProxy::setFrameCompleteCallback(std::function<void(int64_t)>&& callback) {
+void RenderProxy::setFrameCommitCallback(std::function<void(bool)>&& callback) {
+    mDrawFrameTask.setFrameCommitCallback(std::move(callback));
+}
+
+void RenderProxy::setFrameCompleteCallback(std::function<void()>&& callback) {
     mDrawFrameTask.setFrameCompleteCallback(std::move(callback));
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 2b5405c..6417b38 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -124,7 +124,8 @@
             const std::function<bool(int64_t, int64_t, int64_t)>& callback);
     void setPrepareSurfaceControlForWebviewCallback(const std::function<void()>& callback);
     void setFrameCallback(std::function<void(int64_t)>&& callback);
-    void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
+    void setFrameCommitCallback(std::function<void(bool)>&& callback);
+    void setFrameCompleteCallback(std::function<void()>&& callback);
 
     void addFrameMetricsObserver(FrameMetricsObserver* observer);
     void removeFrameMetricsObserver(FrameMetricsObserver* observer);
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 1bfdc47..491af43 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -74,7 +74,7 @@
     layerUpdater->setTransform(&transform);
 
     // updateLayer so it's ready to draw
-    layerUpdater->updateLayer(true, 0, SkRect::MakeEmpty(), nullptr);
+    layerUpdater->updateLayer(true, nullptr, 0, SkRect::MakeEmpty());
     return layerUpdater;
 }
 
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index ca84aee..0c389bfe8 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -38,18 +38,14 @@
     EXPECT_FALSE(layerUpdater->backingLayer()->isBlend());
 
     // push the deferred updates to the layer
-    uint32_t textureTransform = 1;
     SkBitmap bitmap;
     bitmap.allocN32Pixels(16, 16);
-    SkRect cropRect = SkRect::MakeIWH(10, 10);
     sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap);
-    layerUpdater->updateLayer(true, textureTransform, cropRect, layerImage);
+    layerUpdater->updateLayer(true, layerImage, 0, SkRect::MakeEmpty());
 
     // the backing layer should now have all the properties applied.
     EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth());
     EXPECT_EQ(100u, layerUpdater->backingLayer()->getHeight());
     EXPECT_TRUE(layerUpdater->backingLayer()->getForceFilter());
     EXPECT_TRUE(layerUpdater->backingLayer()->isBlend());
-    EXPECT_EQ(textureTransform, layerUpdater->backingLayer()->getTextureTransform());
-    EXPECT_EQ(cropRect, layerUpdater->backingLayer()->getCropRect());
 }
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index acd8bce..0c6dac0 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -153,8 +153,7 @@
                     || update.state.surfaceHeight < desiredHeight) {
                 needApplyTransaction = true;
 
-                t.setSize(update.state.surfaceControl,
-                        desiredWidth, desiredHeight);
+                update.state.surfaceControl->updateDefaultBufferSize(desiredWidth, desiredHeight);
                 update.state.surfaceWidth = desiredWidth;
                 update.state.surfaceHeight = desiredHeight;
                 update.state.surfaceDrawn = false;
@@ -169,7 +168,8 @@
 
         // If surface is a new one, we have to set right layer stack.
         if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) {
-            t.setLayerStack(update.state.surfaceControl, update.state.displayId);
+            t.setLayerStack(update.state.surfaceControl,
+                            ui::LayerStack::fromValue(update.state.displayId));
             needApplyTransaction = true;
         }
     }
diff --git a/location/java/android/location/CorrelationVector.java b/location/java/android/location/CorrelationVector.java
index 718977f..5493e25 100644
--- a/location/java/android/location/CorrelationVector.java
+++ b/location/java/android/location/CorrelationVector.java
@@ -94,8 +94,6 @@
                 "FrequencyOffsetMetersPerSecond must be non-negative (greater than or equal to 0)");
         Preconditions.checkArgument(builder.mSamplingWidthMeters > 0.0,
                 "SamplingWidthMeters must be positive (greater than 0)");
-        Preconditions.checkArgument(builder.mSamplingStartMeters >= 0.0,
-                "SamplingStartMeters must be non-negative (greater than or equal to 0)");
         mMagnitude = builder.mMagnitude;
         mFrequencyOffsetMetersPerSecond = builder.mFrequencyOffsetMetersPerSecond;
         mSamplingWidthMeters = builder.mSamplingWidthMeters;
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 1e8b952..1fcb194 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -18,11 +18,12 @@
 
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,48 +31,51 @@
 import android.util.Printer;
 import android.util.TimeUtils;
 
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.DecimalFormat;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.StringTokenizer;
 
 /**
- * A data class representing a geographic location.
- *
- * <p>A location may consist of a latitude, longitude, timestamp, and other information such as
- * bearing, altitude and velocity.
+ * A data class representing a geographic location. A location consists of a latitude, longitude,
+ * timestamp, accuracy, and other information such as bearing, altitude and velocity.
  *
  * <p>All locations generated through {@link LocationManager} are guaranteed to have a valid
- * latitude, longitude, and timestamp (both UTC time and elapsed real-time since boot). All other
- * parameters are optional.
+ * latitude, longitude, timestamp (both UTC time and elapsed real-time since boot), and accuracy.
+ * All other parameters are optional.
  */
 public class Location implements Parcelable {
 
     /**
-     * Constant used to specify formatting of a latitude or longitude
-     * in the form "[+-]DDD.DDDDD where D indicates degrees.
+     * Constant used to specify formatting of a latitude or longitude in the form "[+-]DDD.DDDDD
+     * where D indicates degrees.
      */
     public static final int FORMAT_DEGREES = 0;
 
     /**
-     * Constant used to specify formatting of a latitude or longitude
-     * in the form "[+-]DDD:MM.MMMMM" where D indicates degrees and
-     * M indicates minutes of arc (1 minute = 1/60th of a degree).
+     * Constant used to specify formatting of a latitude or longitude in the form "[+-]DDD:MM.MMMMM"
+     * where D indicates degrees and M indicates minutes of arc (1 minute = 1/60th of a degree).
      */
     public static final int FORMAT_MINUTES = 1;
 
     /**
-     * Constant used to specify formatting of a latitude or longitude
-     * in the form "DDD:MM:SS.SSSSS" where D indicates degrees, M
-     * indicates minutes of arc, and S indicates seconds of arc (1
+     * Constant used to specify formatting of a latitude or longitude in the form "DDD:MM:SS.SSSSS"
+     * where D indicates degrees, M indicates minutes of arc, and S indicates seconds of arc (1
      * minute = 1/60th of a degree, 1 second = 1/3600th of a degree).
      */
     public static final int FORMAT_SECONDS = 2;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FORMAT_DEGREES, FORMAT_MINUTES, FORMAT_SECONDS})
+    public @interface Format {}
+
     /**
      * Bundle key for a version of the location containing no GPS data.
-     * Allows location providers to flag locations as being safe to
-     * feed to LocationFudger.
      *
      * @hide
      * @deprecated As of Android R, this extra is longer in use, since it is not necessary to keep
@@ -87,7 +91,7 @@
     private static final int HAS_BEARING_MASK = 1 << 2;
     private static final int HAS_HORIZONTAL_ACCURACY_MASK = 1 << 3;
     private static final int HAS_MOCK_PROVIDER_MASK = 1 << 4;
-    private static final int HAS_VERTICAL_ACCURACY_MASK = 1 << 5;
+    private static final int HAS_ALTITUDE_ACCURACY_MASK = 1 << 5;
     private static final int HAS_SPEED_ACCURACY_MASK = 1 << 6;
     private static final int HAS_BEARING_ACCURACY_MASK = 1 << 7;
     private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 1 << 8;
@@ -98,358 +102,86 @@
     private static final ThreadLocal<BearingDistanceCache> sBearingDistanceCache =
             ThreadLocal.withInitial(BearingDistanceCache::new);
 
-    private String mProvider;
-    private long mTime = 0;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
-            publicAlternatives = "{@link #getElapsedRealtimeNanos()}")
-    private long mElapsedRealtimeNanos = 0;
-    // Estimate of the relative precision of the alignment of this SystemClock
-    // timestamp, with the reported measurements in nanoseconds (68% confidence).
-    private double mElapsedRealtimeUncertaintyNanos = 0.0f;
-    private double mLatitude = 0.0;
-    private double mLongitude = 0.0;
-    private double mAltitude = 0.0f;
-    private float mSpeed = 0.0f;
-    private float mBearing = 0.0f;
-    private float mHorizontalAccuracyMeters = 0.0f;
-    private float mVerticalAccuracyMeters = 0.0f;
-    private float mSpeedAccuracyMetersPerSecond = 0.0f;
-    private float mBearingAccuracyDegrees = 0.0f;
-
-    private Bundle mExtras = null;
-
     // A bitmask of fields present in this object (see HAS_* constants defined above).
     private int mFieldsMask = 0;
 
+    private @Nullable String mProvider;
+    private long mTimeMs;
+    private long mElapsedRealtimeNs;
+    private double mElapsedRealtimeUncertaintyNs;
+    private double mLatitudeDegrees;
+    private double mLongitudeDegrees;
+    private float mHorizontalAccuracyMeters;
+    private double mAltitudeMeters;
+    private float mAltitudeAccuracyMeters;
+    private float mSpeedMetersPerSecond;
+    private float mSpeedAccuracyMetersPerSecond;
+    private float mBearingDegrees;
+    private float mBearingAccuracyDegrees;
+
+    private Bundle mExtras = null;
+
     /**
-     * Construct a new Location with a named provider.
+     * Constructs a new location with a named provider. By default all values are zero, and no
+     * optional values are present.
      *
-     * <p>By default time, latitude and longitude are 0, and the location
-     * has no bearing, altitude, speed, accuracy or extras.
-     *
-     * @param provider the source that provides the location. It can be of type
-     * {@link LocationManager#GPS_PROVIDER}, {@link LocationManager#NETWORK_PROVIDER},
-     * or {@link LocationManager#PASSIVE_PROVIDER}. You can also define your own
-     * provider string, in which case an empty string is a valid provider.
+     * @param provider the location provider name associated with this location
      */
-    public Location(String provider) {
+    public Location(@Nullable String provider) {
         mProvider = provider;
     }
 
     /**
      * Construct a new Location object that is copied from an existing one.
      */
-    public Location(Location l) {
+    public Location(@NonNull Location l) {
         set(l);
     }
 
     /**
-     * Sets the contents of the location to the values from the given location.
+     * Turns this location into a copy of the given location.
      */
-    public void set(Location l) {
-        mProvider = l.mProvider;
-        mTime = l.mTime;
-        mElapsedRealtimeNanos = l.mElapsedRealtimeNanos;
-        mElapsedRealtimeUncertaintyNanos = l.mElapsedRealtimeUncertaintyNanos;
+    public void set(@NonNull Location l) {
         mFieldsMask = l.mFieldsMask;
-        mLatitude = l.mLatitude;
-        mLongitude = l.mLongitude;
-        mAltitude = l.mAltitude;
-        mSpeed = l.mSpeed;
-        mBearing = l.mBearing;
+        mProvider = l.mProvider;
+        mTimeMs = l.mTimeMs;
+        mElapsedRealtimeNs = l.mElapsedRealtimeNs;
+        mElapsedRealtimeUncertaintyNs = l.mElapsedRealtimeUncertaintyNs;
+        mLatitudeDegrees = l.mLatitudeDegrees;
+        mLongitudeDegrees = l.mLongitudeDegrees;
         mHorizontalAccuracyMeters = l.mHorizontalAccuracyMeters;
-        mVerticalAccuracyMeters = l.mVerticalAccuracyMeters;
+        mAltitudeMeters = l.mAltitudeMeters;
+        mAltitudeAccuracyMeters = l.mAltitudeAccuracyMeters;
+        mSpeedMetersPerSecond = l.mSpeedMetersPerSecond;
         mSpeedAccuracyMetersPerSecond = l.mSpeedAccuracyMetersPerSecond;
+        mBearingDegrees = l.mBearingDegrees;
         mBearingAccuracyDegrees = l.mBearingAccuracyDegrees;
         mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
     }
 
     /**
-     * Clears the contents of the location.
+     * Sets the provider to null, removes all optional fields, and sets the values of all other
+     * fields to zero.
      */
     public void reset() {
         mProvider = null;
-        mTime = 0;
-        mElapsedRealtimeNanos = 0;
-        mElapsedRealtimeUncertaintyNanos = 0.0;
+        mTimeMs = 0;
+        mElapsedRealtimeNs = 0;
+        mElapsedRealtimeUncertaintyNs = 0.0;
         mFieldsMask = 0;
-        mLatitude = 0;
-        mLongitude = 0;
-        mAltitude = 0;
-        mSpeed = 0;
-        mBearing = 0;
+        mLatitudeDegrees = 0;
+        mLongitudeDegrees = 0;
+        mAltitudeMeters = 0;
+        mSpeedMetersPerSecond = 0;
+        mBearingDegrees = 0;
         mHorizontalAccuracyMeters = 0;
-        mVerticalAccuracyMeters = 0;
+        mAltitudeAccuracyMeters = 0;
         mSpeedAccuracyMetersPerSecond = 0;
         mBearingAccuracyDegrees = 0;
         mExtras = null;
     }
 
     /**
-     * Converts a coordinate to a String representation. The outputType
-     * may be one of FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
-     * The coordinate must be a valid double between -180.0 and 180.0.
-     * This conversion is performed in a method that is dependent on the
-     * default locale, and so is not guaranteed to round-trip with
-     * {@link #convert(String)}.
-     *
-     * @throws IllegalArgumentException if coordinate is less than
-     * -180.0, greater than 180.0, or is not a number.
-     * @throws IllegalArgumentException if outputType is not one of
-     * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
-     */
-    public static String convert(double coordinate, int outputType) {
-        if (coordinate < -180.0 || coordinate > 180.0 || Double.isNaN(coordinate)) {
-            throw new IllegalArgumentException("coordinate=" + coordinate);
-        }
-        if ((outputType != FORMAT_DEGREES) &&
-            (outputType != FORMAT_MINUTES) &&
-            (outputType != FORMAT_SECONDS)) {
-            throw new IllegalArgumentException("outputType=" + outputType);
-        }
-
-        StringBuilder sb = new StringBuilder();
-
-        // Handle negative values
-        if (coordinate < 0) {
-            sb.append('-');
-            coordinate = -coordinate;
-        }
-
-        DecimalFormat df = new DecimalFormat("###.#####");
-        if (outputType == FORMAT_MINUTES || outputType == FORMAT_SECONDS) {
-            int degrees = (int) Math.floor(coordinate);
-            sb.append(degrees);
-            sb.append(':');
-            coordinate -= degrees;
-            coordinate *= 60.0;
-            if (outputType == FORMAT_SECONDS) {
-                int minutes = (int) Math.floor(coordinate);
-                sb.append(minutes);
-                sb.append(':');
-                coordinate -= minutes;
-                coordinate *= 60.0;
-            }
-        }
-        sb.append(df.format(coordinate));
-        return sb.toString();
-    }
-
-    /**
-     * Converts a String in one of the formats described by
-     * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS into a
-     * double. This conversion is performed in a locale agnostic
-     * method, and so is not guaranteed to round-trip with
-     * {@link #convert(double, int)}.
-     *
-     * @throws NullPointerException if coordinate is null
-     * @throws IllegalArgumentException if the coordinate is not
-     * in one of the valid formats.
-     */
-    public static double convert(String coordinate) {
-        // IllegalArgumentException if bad syntax
-        if (coordinate == null) {
-            throw new NullPointerException("coordinate");
-        }
-
-        boolean negative = false;
-        if (coordinate.charAt(0) == '-') {
-            coordinate = coordinate.substring(1);
-            negative = true;
-        }
-
-        StringTokenizer st = new StringTokenizer(coordinate, ":");
-        int tokens = st.countTokens();
-        if (tokens < 1) {
-            throw new IllegalArgumentException("coordinate=" + coordinate);
-        }
-        try {
-            String degrees = st.nextToken();
-            double val;
-            if (tokens == 1) {
-                val = Double.parseDouble(degrees);
-                return negative ? -val : val;
-            }
-
-            String minutes = st.nextToken();
-            int deg = Integer.parseInt(degrees);
-            double min;
-            double sec = 0.0;
-            boolean secPresent = false;
-
-            if (st.hasMoreTokens()) {
-                min = Integer.parseInt(minutes);
-                String seconds = st.nextToken();
-                sec = Double.parseDouble(seconds);
-                secPresent = true;
-            } else {
-                min = Double.parseDouble(minutes);
-            }
-
-            boolean isNegative180 = negative && (deg == 180) &&
-                (min == 0) && (sec == 0);
-
-            // deg must be in [0, 179] except for the case of -180 degrees
-            if ((deg < 0.0) || (deg > 179 && !isNegative180)) {
-                throw new IllegalArgumentException("coordinate=" + coordinate);
-            }
-
-            // min must be in [0, 59] if seconds are present, otherwise [0.0, 60.0)
-            if (min < 0 || min >= 60 || (secPresent && (min > 59))) {
-                throw new IllegalArgumentException("coordinate=" +
-                        coordinate);
-            }
-
-            // sec must be in [0.0, 60.0)
-            if (sec < 0 || sec >= 60) {
-                throw new IllegalArgumentException("coordinate=" +
-                        coordinate);
-            }
-
-            val = deg*3600.0 + min*60.0 + sec;
-            val /= 3600.0;
-            return negative ? -val : val;
-        } catch (NumberFormatException nfe) {
-            throw new IllegalArgumentException("coordinate=" + coordinate);
-        }
-    }
-
-    private static void computeDistanceAndBearing(double lat1, double lon1,
-        double lat2, double lon2, BearingDistanceCache results) {
-        // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
-        // using the "Inverse Formula" (section 4)
-
-        int MAXITERS = 20;
-        // Convert lat/long to radians
-        lat1 *= Math.PI / 180.0;
-        lat2 *= Math.PI / 180.0;
-        lon1 *= Math.PI / 180.0;
-        lon2 *= Math.PI / 180.0;
-
-        double a = 6378137.0; // WGS84 major axis
-        double b = 6356752.3142; // WGS84 semi-major axis
-        double f = (a - b) / a;
-        double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
-
-        double L = lon2 - lon1;
-        double A = 0.0;
-        double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
-        double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
-
-        double cosU1 = Math.cos(U1);
-        double cosU2 = Math.cos(U2);
-        double sinU1 = Math.sin(U1);
-        double sinU2 = Math.sin(U2);
-        double cosU1cosU2 = cosU1 * cosU2;
-        double sinU1sinU2 = sinU1 * sinU2;
-
-        double sigma = 0.0;
-        double deltaSigma = 0.0;
-        double cosSqAlpha;
-        double cos2SM;
-        double cosSigma;
-        double sinSigma;
-        double cosLambda = 0.0;
-        double sinLambda = 0.0;
-
-        double lambda = L; // initial guess
-        for (int iter = 0; iter < MAXITERS; iter++) {
-            double lambdaOrig = lambda;
-            cosLambda = Math.cos(lambda);
-            sinLambda = Math.sin(lambda);
-            double t1 = cosU2 * sinLambda;
-            double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
-            double sinSqSigma = t1 * t1 + t2 * t2; // (14)
-            sinSigma = Math.sqrt(sinSqSigma);
-            cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
-            sigma = Math.atan2(sinSigma, cosSigma); // (16)
-            double sinAlpha = (sinSigma == 0) ? 0.0 :
-                cosU1cosU2 * sinLambda / sinSigma; // (17)
-            cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
-            cos2SM = (cosSqAlpha == 0) ? 0.0 :
-                cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
-
-            double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
-            A = 1 + (uSquared / 16384.0) * // (3)
-                (4096.0 + uSquared *
-                 (-768 + uSquared * (320.0 - 175.0 * uSquared)));
-            double B = (uSquared / 1024.0) * // (4)
-                (256.0 + uSquared *
-                 (-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
-            double C = (f / 16.0) *
-                cosSqAlpha *
-                (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
-            double cos2SMSq = cos2SM * cos2SM;
-            deltaSigma = B * sinSigma * // (6)
-                (cos2SM + (B / 4.0) *
-                 (cosSigma * (-1.0 + 2.0 * cos2SMSq) -
-                  (B / 6.0) * cos2SM *
-                  (-3.0 + 4.0 * sinSigma * sinSigma) *
-                  (-3.0 + 4.0 * cos2SMSq)));
-
-            lambda = L +
-                (1.0 - C) * f * sinAlpha *
-                (sigma + C * sinSigma *
-                 (cos2SM + C * cosSigma *
-                  (-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
-
-            double delta = (lambda - lambdaOrig) / lambda;
-            if (Math.abs(delta) < 1.0e-12) {
-                break;
-            }
-        }
-
-        results.mDistance = (float) (b * A * (sigma - deltaSigma));
-        float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
-            cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
-        initialBearing *= 180.0 / Math.PI;
-        results.mInitialBearing = initialBearing;
-        float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
-                -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
-        finalBearing *= 180.0 / Math.PI;
-        results.mFinalBearing = finalBearing;
-        results.mLat1 = lat1;
-        results.mLat2 = lat2;
-        results.mLon1 = lon1;
-        results.mLon2 = lon2;
-    }
-
-    /**
-     * Computes the approximate distance in meters between two
-     * locations, and optionally the initial and final bearings of the
-     * shortest path between them.  Distance and bearing are defined using the
-     * WGS84 ellipsoid.
-     *
-     * <p> The computed distance is stored in results[0].  If results has length
-     * 2 or greater, the initial bearing is stored in results[1]. If results has
-     * length 3 or greater, the final bearing is stored in results[2].
-     *
-     * @param startLatitude the starting latitude
-     * @param startLongitude the starting longitude
-     * @param endLatitude the ending latitude
-     * @param endLongitude the ending longitude
-     * @param results an array of floats to hold the results
-     *
-     * @throws IllegalArgumentException if results is null or has length < 1
-     */
-    public static void distanceBetween(double startLatitude, double startLongitude,
-        double endLatitude, double endLongitude, float[] results) {
-        if (results == null || results.length < 1) {
-            throw new IllegalArgumentException("results is null or has length < 1");
-        }
-        BearingDistanceCache cache = sBearingDistanceCache.get();
-        computeDistanceAndBearing(startLatitude, startLongitude,
-                endLatitude, endLongitude, cache);
-        results[0] = cache.mDistance;
-        if (results.length > 1) {
-            results[1] = cache.mInitialBearing;
-            if (results.length > 2) {
-                results[2] = cache.mFinalBearing;
-            }
-        }
-    }
-
-    /**
      * Returns the approximate distance in meters between this
      * location and the given location.  Distance is defined using
      * the WGS84 ellipsoid.
@@ -457,13 +189,13 @@
      * @param dest the destination location
      * @return the approximate distance in meters
      */
-    public float distanceTo(Location dest) {
+    public @FloatRange float distanceTo(@NonNull Location dest) {
         BearingDistanceCache cache = sBearingDistanceCache.get();
         // See if we already have the result
-        if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 ||
-            dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) {
-            computeDistanceAndBearing(mLatitude, mLongitude,
-                dest.mLatitude, dest.mLongitude, cache);
+        if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1
+                || dest.mLatitudeDegrees != cache.mLat2 || dest.mLongitudeDegrees != cache.mLon2) {
+            computeDistanceAndBearing(mLatitudeDegrees, mLongitudeDegrees,
+                    dest.mLatitudeDegrees, dest.mLongitudeDegrees, cache);
         }
         return cache.mDistance;
     }
@@ -478,30 +210,32 @@
      * @param dest the destination location
      * @return the initial bearing in degrees
      */
-    public float bearingTo(Location dest) {
+    public float bearingTo(@NonNull Location dest) {
         BearingDistanceCache cache = sBearingDistanceCache.get();
         // See if we already have the result
-        if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 ||
-                        dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) {
-            computeDistanceAndBearing(mLatitude, mLongitude,
-                dest.mLatitude, dest.mLongitude, cache);
+        if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1
+                || dest.mLatitudeDegrees != cache.mLat2 || dest.mLongitudeDegrees != cache.mLon2) {
+            computeDistanceAndBearing(mLatitudeDegrees, mLongitudeDegrees,
+                    dest.mLatitudeDegrees, dest.mLongitudeDegrees, cache);
         }
         return cache.mInitialBearing;
     }
 
     /**
-     * Returns the name of the provider that generated this fix.
+     * Returns the name of the provider associated with this location.
      *
-     * @return the provider, or null if it has not been set
+     * @return the name of the provider
      */
-    public String getProvider() {
+    public @Nullable String getProvider() {
         return mProvider;
     }
 
     /**
-     * Sets the name of the provider that generated this fix.
+     * Sets the name of the provider associated with this location
+     *
+     * @param provider the name of the provider
      */
-    public void setProvider(String provider) {
+    public void setProvider(@Nullable String provider) {
         mProvider = provider;
     }
 
@@ -526,19 +260,19 @@
      * set, however remember that the device clock may have changed since the location was
      * generated.
      *
-     * @return UTC time of fix, in milliseconds since January 1, 1970.
+     * @return UTC time of this location
      */
-    public long getTime() {
-        return mTime;
+    public @IntRange long getTime() {
+        return mTimeMs;
     }
 
     /**
-     * Set the UTC time of this fix, in milliseconds since epoch (January 1, 1970).
+     * Set the UTC time of this location, in milliseconds since epoch (January 1, 1970).
      *
-     * @param time UTC time of this fix, in milliseconds since January 1, 1970
+     * @param timeMs UTC time of this location
      */
-    public void setTime(long time) {
-        mTime = time;
+    public void setTime(@IntRange long timeMs) {
+        mTimeMs = timeMs;
     }
 
     /**
@@ -548,716 +282,413 @@
      * reliably order or compare locations. This is reliable because elapsed realtime is guaranteed
      * to be monotonic and continues to increment even when the system is in deep sleep (unlike
      * {@link #getTime}). However, since elapsed realtime is with reference to system boot, it does
-     * not make sense to use this value to order or compare locations across boot cycles.
+     * not make sense to use this value to order or compare locations across boot cycles or devices.
      *
      * <p>All locations generated by the {@link LocationManager} are guaranteed to have a valid
      * elapsed realtime set.
      *
-     * @return elapsed realtime of fix, in nanoseconds since system boot.
+     * @return elapsed realtime of this location in nanoseconds
      */
-    public long getElapsedRealtimeNanos() {
-        return mElapsedRealtimeNanos;
+    public @IntRange long getElapsedRealtimeNanos() {
+        return mElapsedRealtimeNs;
     }
 
     /**
      * Return the time of this fix in milliseconds of elapsed realtime since system boot.
      *
+     * @return elapsed realtime of this location in milliseconds
      * @see #getElapsedRealtimeNanos()
-     *
-     * @hide
      */
-    public long getElapsedRealtimeMillis() {
-        return NANOSECONDS.toMillis(getElapsedRealtimeNanos());
+    public @IntRange long getElapsedRealtimeMillis() {
+        return NANOSECONDS.toMillis(mElapsedRealtimeNs);
     }
 
     /**
-     * Returns the age of this fix with respect to the current elapsed realtime.
+     * A convenience methods that returns the age of this location in milliseconds with respect to
+     * the current elapsed realtime.
      *
-     * @see #getElapsedRealtimeNanos()
-     *
-     * @hide
+     * @return age of this location in milliseconds
      */
-    public long getElapsedRealtimeAgeMillis() {
+    public @IntRange long getElapsedRealtimeAgeMillis() {
         return getElapsedRealtimeAgeMillis(SystemClock.elapsedRealtime());
     }
 
     /**
-     * Returns the age of this fix with respect to the given elapsed realtime.
+     * A convenience method that returns the age of this location with respect to the given
+     * reference elapsed realtime.
      *
-     * @see #getElapsedRealtimeNanos()
-     *
-     * @hide
+     * @param referenceRealtimeMs reference realtime in milliseconds
+     * @return age of this location in milliseconds
      */
-    public long getElapsedRealtimeAgeMillis(long referenceRealtimeMs) {
-        return referenceRealtimeMs - NANOSECONDS.toMillis(mElapsedRealtimeNanos);
+    public @IntRange long getElapsedRealtimeAgeMillis(@IntRange long referenceRealtimeMs) {
+        return referenceRealtimeMs - getElapsedRealtimeMillis();
     }
 
     /**
-     * Set the time of this fix, in elapsed realtime since system boot.
+     * Set the time of this location in nanoseconds of elapsed realtime since system boot.
      *
-     * @param time elapsed realtime of fix, in nanoseconds since system boot.
+     * @param elapsedRealtimeNs elapsed realtime in nanoseconds
      */
-    public void setElapsedRealtimeNanos(long time) {
-        mElapsedRealtimeNanos = time;
+    public void setElapsedRealtimeNanos(@IntRange long elapsedRealtimeNs) {
+        mElapsedRealtimeNs = elapsedRealtimeNs;
     }
 
     /**
-     * Get estimate of the relative precision of the alignment of the
-     * ElapsedRealtimeNanos timestamp, with the reported measurements in
-     * nanoseconds (68% confidence).
+     * Get the uncertainty in nanoseconds of the precision of {@link #getElapsedRealtimeNanos()} at
+     * the 68th percentile confidence level. This means that there is 68% chance that the true
+     * elapsed realtime of this location is within {@link #getElapsedRealtimeNanos()} +/- this
+     * uncertainty.
      *
-     * This means that we have 68% confidence that the true timestamp of the
-     * event is within ElapsedReatimeNanos +/- uncertainty.
+     * <p>This is only valid if {@link #hasElapsedRealtimeUncertaintyNanos()} is true.
      *
-     * Example :
-     *   - getElapsedRealtimeNanos() returns 10000000
-     *   - getElapsedRealtimeUncertaintyNanos() returns 1000000 (equivalent to 1millisecond)
-     *   This means that the event most likely happened between 9000000 and 11000000.
-     *
-     * @return uncertainty of elapsed real-time of fix, in nanoseconds.
+     * @return uncertainty in nanoseconds of the elapsed realtime of this location
      */
-    public double getElapsedRealtimeUncertaintyNanos() {
-        return mElapsedRealtimeUncertaintyNanos;
+    public @FloatRange double getElapsedRealtimeUncertaintyNanos() {
+        return mElapsedRealtimeUncertaintyNs;
     }
 
     /**
-     * Set estimate of the relative precision of the alignment of the
-     * ElapsedRealtimeNanos timestamp, with the reported measurements in
-     * nanoseconds (68% confidence).
+     * Sets the uncertainty in nanoseconds of the precision of the elapsed realtime timestamp at a
+     * 68% confidence level.
      *
-     * @param time uncertainty of the elapsed real-time of fix, in nanoseconds.
+     * @param elapsedRealtimeUncertaintyNs uncertainty in nanoseconds of the elapsed realtime of
+     *                                     this location
      */
-    public void setElapsedRealtimeUncertaintyNanos(double time) {
-        mElapsedRealtimeUncertaintyNanos = time;
+    public void setElapsedRealtimeUncertaintyNanos(
+            @FloatRange double elapsedRealtimeUncertaintyNs) {
+        mElapsedRealtimeUncertaintyNs = elapsedRealtimeUncertaintyNs;
         mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
     }
 
     /**
-     * True if this location has a elapsed realtime accuracy.
+     * True if this location has a elapsed realtime uncertainty, false otherwise.
      */
     public boolean hasElapsedRealtimeUncertaintyNanos() {
         return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0;
     }
 
-
     /**
-     * Get the latitude, in degrees.
-     *
-     * <p>All locations generated by the {@link LocationManager}
-     * will have a valid latitude.
+     * Removes the elapsed realtime uncertainy from this location.
      */
-    public double getLatitude() {
-        return mLatitude;
+    public void removeElapsedRealtimeUncertaintyNanos() {
+        mFieldsMask &= ~HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
     }
 
     /**
-     * Set the latitude, in degrees.
+     * Get the latitude in degrees. All locations generated by the {@link LocationManager} will have
+     * a valid latitude.
+     *
+     * @return latitude of this location
      */
-    public void setLatitude(double latitude) {
-        mLatitude = latitude;
+    public @FloatRange double getLatitude() {
+        return mLatitudeDegrees;
     }
 
     /**
-     * Get the longitude, in degrees.
+     * Set the latitude of this location.
      *
-     * <p>All locations generated by the {@link LocationManager}
-     * will have a valid longitude.
+     * @param latitudeDegrees latitude in degrees
      */
-    public double getLongitude() {
-        return mLongitude;
+    public void setLatitude(@FloatRange double latitudeDegrees) {
+        mLatitudeDegrees = latitudeDegrees;
     }
 
     /**
-     * Set the longitude, in degrees.
+     * Get the longitude in degrees. All locations generated by the {@link LocationManager} will
+     * have a valid longitude.
+     *
+     * @return longitude of this location
      */
-    public void setLongitude(double longitude) {
-        mLongitude = longitude;
+    public @FloatRange double getLongitude() {
+        return mLongitudeDegrees;
     }
 
     /**
-     * True if this location has an altitude.
+     * Set the longitude of this location.
+     *
+     * @param longitudeDegrees longitude in degrees
      */
-    public boolean hasAltitude() {
-        return (mFieldsMask & HAS_ALTITUDE_MASK) != 0;
+    public void setLongitude(@FloatRange double longitudeDegrees) {
+        mLongitudeDegrees = longitudeDegrees;
     }
 
     /**
-     * Get the altitude if available, in meters above the WGS 84 reference
-     * ellipsoid.
+     * Returns the estimated horizontal accuracy radius in meters of this location at the 68th
+     * percentile confidence level. This means that there is a 68% chance that the true location of
+     * the device is within a distance of this uncertainty of the reported location. Another way of
+     * putting this is that if a circle with a radius equal to this accuracy is drawn around the
+     * reported location, there is a 68% chance that the true location falls within this circle.
+     * This accuracy value is only valid for horizontal positioning, and not vertical positioning.
      *
-     * <p>If this location does not have an altitude then 0.0 is returned.
+     * <p>This is only valid if {@link #hasSpeed()} is true. All locations generated by the
+     * {@link LocationManager} include horizontal accuracy.
+     *
+     * @return horizontal accuracy of this location
      */
-    public double getAltitude() {
-        return mAltitude;
+    public @FloatRange float getAccuracy() {
+        return mHorizontalAccuracyMeters;
     }
 
     /**
-     * Set the altitude, in meters above the WGS 84 reference ellipsoid.
+     * Set the horizontal accuracy in meters of this location.
      *
-     * <p>Following this call {@link #hasAltitude} will return true.
+     * @param horizontalAccuracyMeters horizontal altitude in meters
      */
-    public void setAltitude(double altitude) {
-        mAltitude = altitude;
-        mFieldsMask |= HAS_ALTITUDE_MASK;
+    public void setAccuracy(@FloatRange float horizontalAccuracyMeters) {
+        mHorizontalAccuracyMeters = horizontalAccuracyMeters;
+        mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
     }
 
     /**
-     * Remove the altitude from this location.
-     *
-     * <p>Following this call {@link #hasAltitude} will return false,
-     * and {@link #getAltitude} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
-     */
-    @Deprecated
-    public void removeAltitude() {
-        mAltitude = 0.0f;
-        mFieldsMask &= ~HAS_ALTITUDE_MASK;
-    }
-
-    /**
-     * True if this location has a speed.
-     */
-    public boolean hasSpeed() {
-        return (mFieldsMask & HAS_SPEED_MASK) != 0;
-    }
-
-    /**
-     * Get the speed if it is available, in meters/second over ground.
-     *
-     * <p>If this location does not have a speed then 0.0 is returned.
-     */
-    public float getSpeed() {
-        return mSpeed;
-    }
-
-    /**
-     * Set the speed, in meters/second over ground.
-     *
-     * <p>Following this call {@link #hasSpeed} will return true.
-     */
-    public void setSpeed(float speed) {
-        mSpeed = speed;
-        mFieldsMask |= HAS_SPEED_MASK;
-    }
-
-    /**
-     * Remove the speed from this location.
-     *
-     * <p>Following this call {@link #hasSpeed} will return false,
-     * and {@link #getSpeed} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
-     */
-    @Deprecated
-    public void removeSpeed() {
-        mSpeed = 0.0f;
-        mFieldsMask &= ~HAS_SPEED_MASK;
-    }
-
-    /**
-     * True if this location has a bearing.
-     */
-    public boolean hasBearing() {
-        return (mFieldsMask & HAS_BEARING_MASK) != 0;
-    }
-
-    /**
-     * Get the bearing, in degrees.
-     *
-     * <p>Bearing is the horizontal direction of travel of this device,
-     * and is not related to the device orientation. It is guaranteed to
-     * be in the range (0.0, 360.0] if the device has a bearing.
-     *
-     * <p>If this location does not have a bearing then 0.0 is returned.
-     */
-    public float getBearing() {
-        return mBearing;
-    }
-
-    /**
-     * Set the bearing, in degrees.
-     *
-     * <p>Bearing is the horizontal direction of travel of this device,
-     * and is not related to the device orientation.
-     *
-     * <p>The input will be wrapped into the range (0.0, 360.0].
-     */
-    public void setBearing(float bearing) {
-        while (bearing < 0.0f) {
-            bearing += 360.0f;
-        }
-        while (bearing >= 360.0f) {
-            bearing -= 360.0f;
-        }
-        mBearing = bearing;
-        mFieldsMask |= HAS_BEARING_MASK;
-    }
-
-    /**
-     * Remove the bearing from this location.
-     *
-     * <p>Following this call {@link #hasBearing} will return false,
-     * and {@link #getBearing} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
-     */
-    @Deprecated
-    public void removeBearing() {
-        mBearing = 0.0f;
-        mFieldsMask &= ~HAS_BEARING_MASK;
-    }
-
-    /**
-     * True if this location has a horizontal accuracy.
-     *
-     * <p>All locations generated by the {@link LocationManager} have an horizontal accuracy.
+     * Returns true if this location has a horizontal accuracy, false otherwise.
      */
     public boolean hasAccuracy() {
         return (mFieldsMask & HAS_HORIZONTAL_ACCURACY_MASK) != 0;
     }
 
     /**
-     * Get the estimated horizontal accuracy of this location, radial, in meters.
-     *
-     * <p>We define horizontal accuracy as the radius of 68% confidence. In other
-     * words, if you draw a circle centered at this location's
-     * latitude and longitude, and with a radius equal to the accuracy,
-     * then there is a 68% probability that the true location is inside
-     * the circle.
-     *
-     * <p>This accuracy estimation is only concerned with horizontal
-     * accuracy, and does not indicate the accuracy of bearing,
-     * velocity or altitude if those are included in this Location.
-     *
-     * <p>If this location does not have a horizontal accuracy, then 0.0 is returned.
-     * All locations generated by the {@link LocationManager} include horizontal accuracy.
-     */
-    public float getAccuracy() {
-        return mHorizontalAccuracyMeters;
-    }
-
-    /**
-     * Set the estimated horizontal accuracy of this location, meters.
-     *
-     * <p>See {@link #getAccuracy} for the definition of horizontal accuracy.
-     *
-     * <p>Following this call {@link #hasAccuracy} will return true.
-     */
-    public void setAccuracy(float horizontalAccuracy) {
-        mHorizontalAccuracyMeters = horizontalAccuracy;
-        mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
-    }
-
-    /**
      * Remove the horizontal accuracy from this location.
-     *
-     * <p>Following this call {@link #hasAccuracy} will return false, and
-     * {@link #getAccuracy} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
      */
-    @Deprecated
     public void removeAccuracy() {
-        mHorizontalAccuracyMeters = 0.0f;
         mFieldsMask &= ~HAS_HORIZONTAL_ACCURACY_MASK;
     }
 
     /**
-     * True if this location has a vertical accuracy.
+     * The altitude of this location in meters above the WGS84 reference ellipsoid.
+     *
+     * <p>This is only valid if {@link #hasAltitude()} is true.
+     *
+     * @return altitude of this location
+     */
+    public @FloatRange double getAltitude() {
+        return mAltitudeMeters;
+    }
+
+    /**
+     * Set the altitude of this location in meters above the WGS84 reference ellipsoid.
+     *
+     * @param altitudeMeters altitude in meters
+     */
+    public void setAltitude(@FloatRange double altitudeMeters) {
+        mAltitudeMeters = altitudeMeters;
+        mFieldsMask |= HAS_ALTITUDE_MASK;
+    }
+
+    /**
+     * Returns true if this location has an altitude, false otherwise.
+     */
+    public boolean hasAltitude() {
+        return (mFieldsMask & HAS_ALTITUDE_MASK) != 0;
+    }
+
+    /**
+     * Removes the altitude from this location.
+     */
+    public void removeAltitude() {
+        mFieldsMask &= ~HAS_ALTITUDE_MASK;
+    }
+
+    /**
+     * Returns the estimated altitude accuracy in meters of this location at the 68th percentile
+     * confidence level. This means that there is 68% chance that the true altitude of this location
+     * falls within {@link #getAltitude()} ()} +/- this uncertainty.
+     *
+     * <p>This is only valid if {@link #hasVerticalAccuracy()} is true.
+     *
+     * @return vertical accuracy of this location
+     */
+    public @FloatRange float getVerticalAccuracyMeters() {
+        return mAltitudeAccuracyMeters;
+    }
+
+    /**
+     * Set the altitude accuracy of this location in meters.
+     *
+     * @param altitudeAccuracyMeters altitude accuracy in meters
+     */
+    public void setVerticalAccuracyMeters(@FloatRange float altitudeAccuracyMeters) {
+        mAltitudeAccuracyMeters = altitudeAccuracyMeters;
+        mFieldsMask |= HAS_ALTITUDE_ACCURACY_MASK;
+    }
+
+    /**
+     * Returns true if this location has a vertical accuracy, false otherwise.
      */
     public boolean hasVerticalAccuracy() {
-        return (mFieldsMask & HAS_VERTICAL_ACCURACY_MASK) != 0;
-    }
-
-    /**
-     * Get the estimated vertical accuracy of this location, in meters.
-     *
-     * <p>We define vertical accuracy at 68% confidence. Specifically, as 1-side of the 2-sided
-     * range above and below the estimated altitude reported by {@link #getAltitude()}, within which
-     * there is a 68% probability of finding the true altitude.
-     *
-     * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
-     * considered 1 standard deviation.
-     *
-     * <p>For example, if {@link #getAltitude()} returns 150m, and this method returns 20m then
-     * there is a 68% probability of the true altitude being between 130m and 170m.
-     */
-    public float getVerticalAccuracyMeters() {
-        return mVerticalAccuracyMeters;
-    }
-
-    /**
-     * Set the estimated vertical accuracy of this location, meters.
-     *
-     * <p>See {@link #getVerticalAccuracyMeters} for the definition of vertical accuracy.
-     *
-     * <p>Following this call {@link #hasVerticalAccuracy} will return true.
-     */
-    public void setVerticalAccuracyMeters(float verticalAccuracyMeters) {
-        mVerticalAccuracyMeters = verticalAccuracyMeters;
-        mFieldsMask |= HAS_VERTICAL_ACCURACY_MASK;
+        return (mFieldsMask & HAS_ALTITUDE_ACCURACY_MASK) != 0;
     }
 
     /**
      * Remove the vertical accuracy from this location.
-     *
-     * <p>Following this call {@link #hasVerticalAccuracy} will return false, and
-     * {@link #getVerticalAccuracyMeters} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
-     * @removed
      */
-    @Deprecated
     public void removeVerticalAccuracy() {
-        mVerticalAccuracyMeters = 0.0f;
-        mFieldsMask &= ~HAS_VERTICAL_ACCURACY_MASK;
+        mFieldsMask &= ~HAS_ALTITUDE_ACCURACY_MASK;
     }
 
     /**
-     * True if this location has a speed accuracy.
+     * Returns the speed at the time of this location in meters per second. Note that the speed
+     * returned here may be more accurate than would be obtained simply by calculating
+     * {@code distance / time} for sequential positions, such as if the Doppler measurements from
+     * GNSS satellites are taken into account.
+     *
+     * <p>This is only valid if {@link #hasSpeed()} is true.
+     *
+     * @return speed at the time of this location
+     */
+    public @FloatRange float getSpeed() {
+        return mSpeedMetersPerSecond;
+    }
+
+    /**
+     * Set the speed at the time of this location, in meters per second. Prefer not to set negative
+     * speeds.
+     *
+     * @param speedMetersPerSecond speed in meters per second
+     */
+    public void setSpeed(@FloatRange float speedMetersPerSecond) {
+        mSpeedMetersPerSecond = speedMetersPerSecond;
+        mFieldsMask |= HAS_SPEED_MASK;
+    }
+
+    /**
+     * True if this location has a speed, false otherwise.
+     */
+    public boolean hasSpeed() {
+        return (mFieldsMask & HAS_SPEED_MASK) != 0;
+    }
+
+    /**
+     * Remove the speed from this location.
+     */
+    public void removeSpeed() {
+        mFieldsMask &= ~HAS_SPEED_MASK;
+    }
+
+    /**
+     * Returns the estimated speed accuracy in meters per second of this location at the 68th
+     * percentile confidence level. This means that there is 68% chance that the true speed at the
+     * time of this location falls within {@link #getSpeed()} ()} +/- this uncertainty.
+     *
+     * <p>This is only valid if {@link #hasSpeedAccuracy()} is true.
+     *
+     * @return vertical accuracy of this location
+     */
+    public @FloatRange float getSpeedAccuracyMetersPerSecond() {
+        return mSpeedAccuracyMetersPerSecond;
+    }
+
+    /**
+     * Set the speed accuracy of this location in meters per second.
+     *
+     * @param speedAccuracyMeterPerSecond speed accuracy in meters per second
+     */
+    public void setSpeedAccuracyMetersPerSecond(@FloatRange float speedAccuracyMeterPerSecond) {
+        mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
+        mFieldsMask |= HAS_SPEED_ACCURACY_MASK;
+    }
+
+    /**
+     * Returns true if this location has a speed accuracy, false otherwise.
      */
     public boolean hasSpeedAccuracy() {
         return (mFieldsMask & HAS_SPEED_ACCURACY_MASK) != 0;
     }
 
     /**
-     * Get the estimated speed accuracy of this location, in meters per second.
-     *
-     * <p>We define speed accuracy at 68% confidence. Specifically, as 1-side of the 2-sided range
-     * above and below the estimated speed reported by {@link #getSpeed()}, within which there is a
-     * 68% probability of finding the true speed.
-     *
-     * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
-     * considered 1 standard deviation.
-     *
-     * <p>For example, if {@link #getSpeed()} returns 5m/s, and this method returns 1m/s, then there
-     * is a 68% probability of the true speed being between 4m/s and 6m/s.
-     *
-     * <p>Note that the speed and speed accuracy may be more accurate than would be obtained simply
-     * from differencing sequential positions, such as when the Doppler measurements from GNSS
-     * satellites are taken into account.
-     */
-    public float getSpeedAccuracyMetersPerSecond() {
-        return mSpeedAccuracyMetersPerSecond;
-    }
-
-    /**
-     * Set the estimated speed accuracy of this location, meters per second.
-     *
-     * <p>See {@link #getSpeedAccuracyMetersPerSecond} for the definition of speed accuracy.
-     *
-     * <p>Following this call {@link #hasSpeedAccuracy} will return true.
-     */
-    public void setSpeedAccuracyMetersPerSecond(float speedAccuracyMeterPerSecond) {
-        mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
-        mFieldsMask |= HAS_SPEED_ACCURACY_MASK;
-    }
-
-    /**
      * Remove the speed accuracy from this location.
-     *
-     * <p>Following this call {@link #hasSpeedAccuracy} will return false, and
-     * {@link #getSpeedAccuracyMetersPerSecond} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
-     * @removed
      */
-    @Deprecated
     public void removeSpeedAccuracy() {
-        mSpeedAccuracyMetersPerSecond = 0.0f;
         mFieldsMask &= ~HAS_SPEED_ACCURACY_MASK;
     }
 
     /**
-     * True if this location has a bearing accuracy.
+     * Returns the bearing at the time of this location in degrees. Bearing is the horizontal
+     * direction of travel of this device and is unrelated to the device orientation. The bearing
+     * is guaranteed to be in the range [0, 360).
+     *
+     * <p>This is only valid if {@link #hasBearing()} is true.
+     *
+     * @return bearing at the time of this location
+     */
+    public @FloatRange(from = 0f, to = 360f, toInclusive = false) float getBearing() {
+        return mBearingDegrees;
+    }
+
+    /**
+     * Set the bearing at the time of this location, in degrees. The given bearing will be converted
+     * into the range [0, 360).
+     *
+     * <p class="note">Note: passing in extremely high or low floating point values to this function
+     * may produce strange results due to the intricacies of floating point math.
+     *
+     * @param bearingDegrees bearing in degrees
+     */
+    public void setBearing(
+            @FloatRange(fromInclusive = false, toInclusive = false) float bearingDegrees) {
+        Preconditions.checkArgument(Float.isFinite(bearingDegrees));
+
+        // final addition of zero is to remove -0 results. while these are technically within the
+        // range [0, 360) according to IEEE semantics, this eliminates possible user confusion.
+        float modBearing = bearingDegrees % 360f + 0f;
+        if (modBearing < 0) {
+            modBearing += 360f;
+        }
+        mBearingDegrees = modBearing;
+        mFieldsMask |= HAS_BEARING_MASK;
+    }
+
+    /**
+     * True if this location has a bearing, false otherwise.
+     */
+    public boolean hasBearing() {
+        return (mFieldsMask & HAS_BEARING_MASK) != 0;
+    }
+
+    /**
+     * Remove the bearing from this location.
+     */
+    public void removeBearing() {
+        mFieldsMask &= ~HAS_BEARING_MASK;
+    }
+
+    /**
+     * Returns the estimated bearing accuracy in degrees of this location at the 68th percentile
+     * confidence level. This means that there is 68% chance that the true bearing at the
+     * time of this location falls within {@link #getBearing()} ()} +/- this uncertainty.
+     *
+     * <p>This is only valid if {@link #hasBearingAccuracy()} ()} is true.
+     *
+     * @return bearing accuracy in degrees of this location
+     */
+    public @FloatRange float getBearingAccuracyDegrees() {
+        return mBearingAccuracyDegrees;
+    }
+
+    /**
+     * Set the bearing accuracy in degrees of this location.
+     *
+     * @param bearingAccuracyDegrees bearing accuracy in degrees
+     */
+    public void setBearingAccuracyDegrees(@FloatRange float bearingAccuracyDegrees) {
+        mBearingAccuracyDegrees = bearingAccuracyDegrees;
+        mFieldsMask |= HAS_BEARING_ACCURACY_MASK;
+    }
+
+    /**
+     * Returns true if this location has a bearing accuracy, false otherwise.
      */
     public boolean hasBearingAccuracy() {
         return (mFieldsMask & HAS_BEARING_ACCURACY_MASK) != 0;
     }
 
     /**
-     * Get the estimated bearing accuracy of this location, in degrees.
-     *
-     * <p>We define bearing accuracy at 68% confidence. Specifically, as 1-side of the 2-sided range
-     * on each side of the estimated bearing reported by {@link #getBearing()}, within which there
-     * is a 68% probability of finding the true bearing.
-     *
-     * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
-     * considered 1 standard deviation.
-     *
-     * <p>For example, if {@link #getBearing()} returns 60°, and this method returns 10°, then there
-     * is a 68% probability of the true bearing being between 50° and 70°.
-     */
-    public float getBearingAccuracyDegrees() {
-        return mBearingAccuracyDegrees;
-    }
-
-    /**
-     * Set the estimated bearing accuracy of this location, degrees.
-     *
-     * <p>See {@link #getBearingAccuracyDegrees} for the definition of bearing accuracy.
-     *
-     * <p>Following this call {@link #hasBearingAccuracy} will return true.
-     */
-    public void setBearingAccuracyDegrees(float bearingAccuracyDegrees) {
-        mBearingAccuracyDegrees = bearingAccuracyDegrees;
-        mFieldsMask |= HAS_BEARING_ACCURACY_MASK;
-    }
-
-    /**
      * Remove the bearing accuracy from this location.
-     *
-     * <p>Following this call {@link #hasBearingAccuracy} will return false, and
-     * {@link #getBearingAccuracyDegrees} will return 0.0.
-     *
-     * @deprecated use a new Location object for location updates.
-     * @removed
      */
-    @Deprecated
     public void removeBearingAccuracy() {
-        mBearingAccuracyDegrees = 0.0f;
         mFieldsMask &= ~HAS_BEARING_ACCURACY_MASK;
     }
 
     /**
-     * Return true if this Location object is complete.
-     *
-     * <p>A location object is currently considered complete if it has
-     * a valid provider, accuracy, wall-clock time and elapsed real-time.
-     *
-     * <p>All locations supplied by the {@link LocationManager} to
-     * applications must be complete.
-     *
-     * @see #makeComplete
-     * @hide
-     */
-    @SystemApi
-    public boolean isComplete() {
-        return mProvider != null && hasAccuracy() && mTime != 0 && mElapsedRealtimeNanos != 0;
-    }
-
-    /**
-     * Helper to fill incomplete fields.
-     *
-     * <p>Used to assist in backwards compatibility with
-     * Location objects received from applications.
-     *
-     * @see #isComplete
-     * @hide
-     */
-    @SystemApi
-    public void makeComplete() {
-        if (mProvider == null) mProvider = "?";
-        if (!hasAccuracy()) {
-            mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
-            mHorizontalAccuracyMeters = 100.0f;
-        }
-        if (mTime == 0) mTime = System.currentTimeMillis();
-        if (mElapsedRealtimeNanos == 0) mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
-    }
-
-    /**
-     * Returns additional provider-specific information about the location fix as a Bundle. The keys
-     * and values are determined by the provider.  If no additional information is available, null
-     * is returned.
-     *
-     * <p> A number of common key/value pairs are listed
-     * below. Providers that use any of the keys on this list must
-     * provide the corresponding value as described below.
-     *
-     * <ul>
-     * <li> satellites - the number of satellites used to derive the fix
-     * </ul>
-     */
-    public Bundle getExtras() {
-        return mExtras;
-    }
-
-    /**
-     * Sets the extra information associated with this fix to the given Bundle.
-     *
-     * <p>Note this stores a copy of the given extras, so any changes to extras after calling this
-     * method won't be reflected in the location bundle.
-     */
-    public void setExtras(@Nullable Bundle extras) {
-        mExtras = (extras == null) ? null : new Bundle(extras);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        Location location = (Location) o;
-        return mTime == location.mTime
-                && mElapsedRealtimeNanos == location.mElapsedRealtimeNanos
-                && hasElapsedRealtimeUncertaintyNanos()
-                == location.hasElapsedRealtimeUncertaintyNanos()
-                && (!hasElapsedRealtimeUncertaintyNanos() || Double.compare(
-                location.mElapsedRealtimeUncertaintyNanos, mElapsedRealtimeUncertaintyNanos) == 0)
-                && Double.compare(location.mLatitude, mLatitude) == 0
-                && Double.compare(location.mLongitude, mLongitude) == 0
-                && hasAltitude() == location.hasAltitude()
-                && (!hasAltitude() || Double.compare(location.mAltitude, mAltitude) == 0)
-                && hasSpeed() == location.hasSpeed()
-                && (!hasSpeed() || Float.compare(location.mSpeed, mSpeed) == 0)
-                && hasBearing() == location.hasBearing()
-                && (!hasBearing() || Float.compare(location.mBearing, mBearing) == 0)
-                && hasAccuracy() == location.hasAccuracy()
-                && (!hasAccuracy() || Float.compare(location.mHorizontalAccuracyMeters,
-                mHorizontalAccuracyMeters) == 0)
-                && hasVerticalAccuracy() == location.hasVerticalAccuracy()
-                && (!hasVerticalAccuracy() || Float.compare(location.mVerticalAccuracyMeters,
-                mVerticalAccuracyMeters) == 0)
-                && hasSpeedAccuracy() == location.hasSpeedAccuracy()
-                && (!hasSpeedAccuracy() || Float.compare(location.mSpeedAccuracyMetersPerSecond,
-                mSpeedAccuracyMetersPerSecond) == 0)
-                && hasBearingAccuracy() == location.hasBearingAccuracy()
-                && (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
-                mBearingAccuracyDegrees) == 0)
-                && Objects.equals(mProvider, location.mProvider)
-                && Objects.equals(mExtras, location.mExtras);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mProvider, mElapsedRealtimeNanos, mLatitude, mLongitude);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder s = new StringBuilder();
-        s.append("Location[");
-        s.append(mProvider);
-        s.append(" ").append(String.format(Locale.ROOT, "%.6f,%.6f", mLatitude, mLongitude));
-        if (hasAccuracy()) {
-            s.append(" hAcc=").append(mHorizontalAccuracyMeters);
-        }
-        s.append(" et=");
-        TimeUtils.formatDuration(getElapsedRealtimeMillis(), s);
-        if (hasAltitude()) {
-            s.append(" alt=").append(mAltitude);
-            if (hasVerticalAccuracy()) {
-                s.append(" vAcc=").append(mVerticalAccuracyMeters);
-            }
-        }
-        if (hasSpeed()) {
-            s.append(" vel=").append(mSpeed);
-            if (hasSpeedAccuracy()) {
-                s.append(" sAcc=").append(mSpeedAccuracyMetersPerSecond);
-            }
-        }
-        if (hasBearing()) {
-            s.append(" bear=").append(mBearing);
-            if (hasBearingAccuracy()) {
-                s.append(" bAcc=").append(mBearingAccuracyDegrees);
-            }
-        }
-        if (isMock()) {
-            s.append(" mock");
-        }
-
-        if (mExtras != null) {
-            s.append(" {").append(mExtras).append('}');
-        }
-        s.append(']');
-        return s.toString();
-    }
-
-    public void dump(Printer pw, String prefix) {
-        pw.println(prefix + toString());
-    }
-
-    public static final @NonNull Parcelable.Creator<Location> CREATOR =
-        new Parcelable.Creator<Location>() {
-        @Override
-        public Location createFromParcel(Parcel in) {
-            Location l = new Location(in.readString());
-            l.mFieldsMask = in.readInt();
-            l.mTime = in.readLong();
-            l.mElapsedRealtimeNanos = in.readLong();
-            if (l.hasElapsedRealtimeUncertaintyNanos()) {
-                l.mElapsedRealtimeUncertaintyNanos = in.readDouble();
-            }
-            l.mLatitude = in.readDouble();
-            l.mLongitude = in.readDouble();
-            if (l.hasAltitude()) {
-                l.mAltitude = in.readDouble();
-            }
-            if (l.hasSpeed()) {
-                l.mSpeed = in.readFloat();
-            }
-            if (l.hasBearing()) {
-                l.mBearing = in.readFloat();
-            }
-            if (l.hasAccuracy()) {
-                l.mHorizontalAccuracyMeters = in.readFloat();
-            }
-            if (l.hasVerticalAccuracy()) {
-                l.mVerticalAccuracyMeters = in.readFloat();
-            }
-            if (l.hasSpeedAccuracy()) {
-                l.mSpeedAccuracyMetersPerSecond = in.readFloat();
-            }
-            if (l.hasBearingAccuracy()) {
-                l.mBearingAccuracyDegrees = in.readFloat();
-            }
-            l.mExtras = Bundle.setDefusable(in.readBundle(), true);
-            return l;
-        }
-
-        @Override
-        public Location[] newArray(int size) {
-            return new Location[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeString(mProvider);
-        parcel.writeInt(mFieldsMask);
-        parcel.writeLong(mTime);
-        parcel.writeLong(mElapsedRealtimeNanos);
-        if (hasElapsedRealtimeUncertaintyNanos()) {
-            parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
-        }
-        parcel.writeDouble(mLatitude);
-        parcel.writeDouble(mLongitude);
-        if (hasAltitude()) {
-            parcel.writeDouble(mAltitude);
-        }
-        if (hasSpeed()) {
-            parcel.writeFloat(mSpeed);
-        }
-        if (hasBearing()) {
-            parcel.writeFloat(mBearing);
-        }
-        if (hasAccuracy()) {
-            parcel.writeFloat(mHorizontalAccuracyMeters);
-        }
-        if (hasVerticalAccuracy()) {
-            parcel.writeFloat(mVerticalAccuracyMeters);
-        }
-        if (hasSpeedAccuracy()) {
-            parcel.writeFloat(mSpeedAccuracyMetersPerSecond);
-        }
-        if (hasBearingAccuracy()) {
-            parcel.writeFloat(mBearingAccuracyDegrees);
-        }
-        parcel.writeBundle(mExtras);
-    }
-
-    /**
      * Returns true if the Location came from a mock provider.
      *
      * @return true if this Location came from a mock provider, false otherwise
@@ -1304,9 +735,497 @@
     }
 
     /**
-     * Caches data used to compute distance and bearing (so successive calls to {@link #distanceTo}
-     * and {@link #bearingTo} don't duplicate work.
+     * Returns an optional bundle of additional information associated with this location. The keys
+     * and values within the bundle are determined by the location provider.
+     *
+     * <p> Common key/value pairs are listed below. There is no guarantee that these key/value pairs
+     * will be present for any location.
+     *
+     * <ul>
+     * <li> satellites - the number of satellites used to derive the GNSS fix
+     * </ul>
      */
+    public @Nullable Bundle getExtras() {
+        return mExtras;
+    }
+
+    /**
+     * Sets the extra information associated with this fix to the given Bundle.
+     *
+     * <p>Note this stores a copy of the given extras, so any changes to extras after calling this
+     * method won't be reflected in the location bundle.
+     */
+    public void setExtras(@Nullable Bundle extras) {
+        mExtras = (extras == null) ? null : new Bundle(extras);
+    }
+
+    /**
+     * Return true if this location is considered complete. A location is considered complete if it
+     * has a non-null provider, accuracy, and non-zero time and elapsed realtime. The exact
+     * definition of completeness may change over time.
+     *
+     * <p>All locations supplied by the {@link LocationManager} are guaranteed to be complete.
+     */
+    public boolean isComplete() {
+        return mProvider != null && hasAccuracy() && mTimeMs != 0 && mElapsedRealtimeNs != 0;
+    }
+
+    /**
+     * Helper to fill incomplete fields with valid (but likely nonsensical) values.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void makeComplete() {
+        if (mProvider == null) {
+            mProvider = "";
+        }
+        if (!hasAccuracy()) {
+            mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
+            mHorizontalAccuracyMeters = 100.0f;
+        }
+        if (mTimeMs == 0) {
+            mTimeMs = System.currentTimeMillis();
+        }
+        if (mElapsedRealtimeNs == 0) {
+            mElapsedRealtimeNs = SystemClock.elapsedRealtimeNanos();
+        }
+    }
+
+    /**
+     * Location equality is provided primarily for test purposes. Comparing locations for equality
+     * in production may indicate incorrect assumptions, and should be avoided whenever possible.
+     *
+     * <p>{@inheritDoc}
+     */
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof Location)) {
+            return false;
+        }
+
+        Location location = (Location) o;
+        return mTimeMs == location.mTimeMs
+                && mElapsedRealtimeNs == location.mElapsedRealtimeNs
+                && hasElapsedRealtimeUncertaintyNanos()
+                == location.hasElapsedRealtimeUncertaintyNanos()
+                && (!hasElapsedRealtimeUncertaintyNanos() || Double.compare(
+                location.mElapsedRealtimeUncertaintyNs, mElapsedRealtimeUncertaintyNs) == 0)
+                && Double.compare(location.mLatitudeDegrees, mLatitudeDegrees) == 0
+                && Double.compare(location.mLongitudeDegrees, mLongitudeDegrees) == 0
+                && hasAltitude() == location.hasAltitude()
+                && (!hasAltitude() || Double.compare(location.mAltitudeMeters, mAltitudeMeters)
+                == 0)
+                && hasSpeed() == location.hasSpeed()
+                && (!hasSpeed() || Float.compare(location.mSpeedMetersPerSecond,
+                mSpeedMetersPerSecond) == 0)
+                && hasBearing() == location.hasBearing()
+                && (!hasBearing() || Float.compare(location.mBearingDegrees, mBearingDegrees) == 0)
+                && hasAccuracy() == location.hasAccuracy()
+                && (!hasAccuracy() || Float.compare(location.mHorizontalAccuracyMeters,
+                mHorizontalAccuracyMeters) == 0)
+                && hasVerticalAccuracy() == location.hasVerticalAccuracy()
+                && (!hasVerticalAccuracy() || Float.compare(location.mAltitudeAccuracyMeters,
+                mAltitudeAccuracyMeters) == 0)
+                && hasSpeedAccuracy() == location.hasSpeedAccuracy()
+                && (!hasSpeedAccuracy() || Float.compare(location.mSpeedAccuracyMetersPerSecond,
+                mSpeedAccuracyMetersPerSecond) == 0)
+                && hasBearingAccuracy() == location.hasBearingAccuracy()
+                && (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
+                mBearingAccuracyDegrees) == 0)
+                && Objects.equals(mProvider, location.mProvider)
+                && areExtrasEqual(mExtras, location.mExtras);
+    }
+
+    private static boolean areExtrasEqual(@Nullable Bundle extras1, @Nullable Bundle extras2) {
+        if ((extras1 == null || extras1.isEmpty()) && (extras2 == null || extras2.isEmpty())) {
+            return true;
+        } else if (extras1 == null || extras2 == null) {
+            return false;
+        } else {
+            return extras1.kindofEquals(extras2);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mProvider, mElapsedRealtimeNs, mLatitudeDegrees, mLongitudeDegrees);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("Location[");
+        s.append(mProvider);
+        s.append(" ").append(String.format(Locale.ROOT, "%.6f,%.6f", mLatitudeDegrees,
+                mLongitudeDegrees));
+        if (hasAccuracy()) {
+            s.append(" hAcc=").append(mHorizontalAccuracyMeters);
+        }
+        s.append(" et=");
+        TimeUtils.formatDuration(getElapsedRealtimeMillis(), s);
+        if (hasAltitude()) {
+            s.append(" alt=").append(mAltitudeMeters);
+            if (hasVerticalAccuracy()) {
+                s.append(" vAcc=").append(mAltitudeAccuracyMeters);
+            }
+        }
+        if (hasSpeed()) {
+            s.append(" vel=").append(mSpeedMetersPerSecond);
+            if (hasSpeedAccuracy()) {
+                s.append(" sAcc=").append(mSpeedAccuracyMetersPerSecond);
+            }
+        }
+        if (hasBearing()) {
+            s.append(" bear=").append(mBearingDegrees);
+            if (hasBearingAccuracy()) {
+                s.append(" bAcc=").append(mBearingAccuracyDegrees);
+            }
+        }
+        if (isMock()) {
+            s.append(" mock");
+        }
+
+        if (mExtras != null && !mExtras.isEmpty()) {
+            s.append(" {").append(mExtras).append('}');
+        }
+        s.append(']');
+        return s.toString();
+    }
+
+    /** Dumps location. */
+    public void dump(@NonNull Printer pw, @Nullable String prefix) {
+        pw.println(prefix + this);
+    }
+
+    public static final @NonNull Parcelable.Creator<Location> CREATOR =
+        new Parcelable.Creator<Location>() {
+        @Override
+        public Location createFromParcel(Parcel in) {
+            Location l = new Location(in.readString8());
+            l.mFieldsMask = in.readInt();
+            l.mTimeMs = in.readLong();
+            l.mElapsedRealtimeNs = in.readLong();
+            if (l.hasElapsedRealtimeUncertaintyNanos()) {
+                l.mElapsedRealtimeUncertaintyNs = in.readDouble();
+            }
+            l.mLatitudeDegrees = in.readDouble();
+            l.mLongitudeDegrees = in.readDouble();
+            if (l.hasAltitude()) {
+                l.mAltitudeMeters = in.readDouble();
+            }
+            if (l.hasSpeed()) {
+                l.mSpeedMetersPerSecond = in.readFloat();
+            }
+            if (l.hasBearing()) {
+                l.mBearingDegrees = in.readFloat();
+            }
+            if (l.hasAccuracy()) {
+                l.mHorizontalAccuracyMeters = in.readFloat();
+            }
+            if (l.hasVerticalAccuracy()) {
+                l.mAltitudeAccuracyMeters = in.readFloat();
+            }
+            if (l.hasSpeedAccuracy()) {
+                l.mSpeedAccuracyMetersPerSecond = in.readFloat();
+            }
+            if (l.hasBearingAccuracy()) {
+                l.mBearingAccuracyDegrees = in.readFloat();
+            }
+            l.mExtras = Bundle.setDefusable(in.readBundle(), true);
+            return l;
+        }
+
+        @Override
+        public Location[] newArray(int size) {
+            return new Location[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeString8(mProvider);
+        parcel.writeInt(mFieldsMask);
+        parcel.writeLong(mTimeMs);
+        parcel.writeLong(mElapsedRealtimeNs);
+        if (hasElapsedRealtimeUncertaintyNanos()) {
+            parcel.writeDouble(mElapsedRealtimeUncertaintyNs);
+        }
+        parcel.writeDouble(mLatitudeDegrees);
+        parcel.writeDouble(mLongitudeDegrees);
+        if (hasAltitude()) {
+            parcel.writeDouble(mAltitudeMeters);
+        }
+        if (hasSpeed()) {
+            parcel.writeFloat(mSpeedMetersPerSecond);
+        }
+        if (hasBearing()) {
+            parcel.writeFloat(mBearingDegrees);
+        }
+        if (hasAccuracy()) {
+            parcel.writeFloat(mHorizontalAccuracyMeters);
+        }
+        if (hasVerticalAccuracy()) {
+            parcel.writeFloat(mAltitudeAccuracyMeters);
+        }
+        if (hasSpeedAccuracy()) {
+            parcel.writeFloat(mSpeedAccuracyMetersPerSecond);
+        }
+        if (hasBearingAccuracy()) {
+            parcel.writeFloat(mBearingAccuracyDegrees);
+        }
+        parcel.writeBundle(mExtras);
+    }
+
+    /**
+     * Converts a latitude/longitude coordinate to a String representation. The outputType must be
+     * one of {@link #FORMAT_DEGREES}, {@link #FORMAT_MINUTES}, or {@link #FORMAT_SECONDS}. The
+     * coordinate must be a number between -180.0 and 180.0, inclusive. This conversion is performed
+     * in a method that is dependent on the default locale, and so is not guaranteed to round-trip
+     * with {@link #convert(String)}.
+     *
+     * @throws IllegalArgumentException if coordinate is less than -180.0, greater than 180.0, or is
+     *                                  not a number.
+     * @throws IllegalArgumentException if outputType is not a recognized value.
+     */
+    public static @NonNull String convert(@FloatRange double coordinate, @Format int outputType) {
+        Preconditions.checkArgumentInRange(coordinate, -180D, 180D, "coordinate");
+        Preconditions.checkArgument(outputType == FORMAT_DEGREES || outputType == FORMAT_MINUTES
+                || outputType == FORMAT_SECONDS, "%d is an unrecognized format", outputType);
+
+        StringBuilder sb = new StringBuilder();
+
+        if (coordinate < 0) {
+            sb.append('-');
+            coordinate = -coordinate;
+        }
+
+        DecimalFormat df = new DecimalFormat("###.#####");
+        if (outputType == FORMAT_MINUTES || outputType == FORMAT_SECONDS) {
+            int degrees = (int) Math.floor(coordinate);
+            sb.append(degrees);
+            sb.append(':');
+            coordinate -= degrees;
+            coordinate *= 60.0;
+            if (outputType == FORMAT_SECONDS) {
+                int minutes = (int) Math.floor(coordinate);
+                sb.append(minutes);
+                sb.append(':');
+                coordinate -= minutes;
+                coordinate *= 60.0;
+            }
+        }
+        sb.append(df.format(coordinate));
+        return sb.toString();
+    }
+
+    /**
+     * Converts a String in one of the formats described by {@link #FORMAT_DEGREES},
+     * {@link #FORMAT_MINUTES}, or {@link #FORMAT_SECONDS} into a double. This conversion is
+     * performed in a locale agnostic method, and so is not guaranteed to round-trip with
+     * {@link #convert(double, int)}.
+     *
+     * @throws NullPointerException if coordinate is null
+     * @throws IllegalArgumentException if the coordinate is not
+     * in one of the valid formats.
+     */
+    public static @FloatRange double convert(@NonNull String coordinate) {
+        Objects.requireNonNull(coordinate);
+
+        boolean negative = false;
+        if (coordinate.charAt(0) == '-') {
+            coordinate = coordinate.substring(1);
+            negative = true;
+        }
+
+        StringTokenizer st = new StringTokenizer(coordinate, ":");
+        int tokens = st.countTokens();
+        if (tokens < 1) {
+            throw new IllegalArgumentException("coordinate=" + coordinate);
+        }
+        try {
+            String degrees = st.nextToken();
+            double val;
+            if (tokens == 1) {
+                val = Double.parseDouble(degrees);
+                return negative ? -val : val;
+            }
+
+            String minutes = st.nextToken();
+            int deg = Integer.parseInt(degrees);
+            double min;
+            double sec = 0.0;
+            boolean secPresent = false;
+
+            if (st.hasMoreTokens()) {
+                min = Integer.parseInt(minutes);
+                String seconds = st.nextToken();
+                sec = Double.parseDouble(seconds);
+                secPresent = true;
+            } else {
+                min = Double.parseDouble(minutes);
+            }
+
+            boolean isNegative180 = negative && deg == 180 && min == 0 && sec == 0;
+
+            // deg must be in [0, 179] except for the case of -180 degrees
+            if (deg < 0.0 || (deg > 179 && !isNegative180)) {
+                throw new IllegalArgumentException("coordinate=" + coordinate);
+            }
+
+            // min must be in [0, 59] if seconds are present, otherwise [0.0, 60.0)
+            if (min < 0 || min >= 60 || (secPresent && min > 59)) {
+                throw new IllegalArgumentException("coordinate=" + coordinate);
+            }
+
+            // sec must be in [0.0, 60.0)
+            if (sec < 0 || sec >= 60) {
+                throw new IllegalArgumentException("coordinate=" + coordinate);
+            }
+
+            val = deg * 3600.0 + min * 60.0 + sec;
+            val /= 3600.0;
+            return negative ? -val : val;
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("coordinate=" + coordinate, e);
+        }
+    }
+
+    private static void computeDistanceAndBearing(double lat1, double lon1,
+            double lat2, double lon2, BearingDistanceCache results) {
+        // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+        // using the "Inverse Formula" (section 4)
+
+        // Convert lat/long to radians
+        lat1 *= Math.PI / 180.0;
+        lat2 *= Math.PI / 180.0;
+        lon1 *= Math.PI / 180.0;
+        lon2 *= Math.PI / 180.0;
+
+        double a = 6378137.0; // WGS84 major axis
+        double b = 6356752.3142; // WGS84 semi-major axis
+        double f = (a - b) / a;
+        double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
+
+        double l = lon2 - lon1;
+        double aA = 0.0;
+        double u1 = Math.atan((1.0 - f) * Math.tan(lat1));
+        double u2 = Math.atan((1.0 - f) * Math.tan(lat2));
+
+        double cosU1 = Math.cos(u1);
+        double cosU2 = Math.cos(u2);
+        double sinU1 = Math.sin(u1);
+        double sinU2 = Math.sin(u2);
+        double cosU1cosU2 = cosU1 * cosU2;
+        double sinU1sinU2 = sinU1 * sinU2;
+
+        double sigma = 0.0;
+        double deltaSigma = 0.0;
+        double cosSqAlpha;
+        double cos2SM;
+        double cosSigma;
+        double sinSigma;
+        double cosLambda = 0.0;
+        double sinLambda = 0.0;
+
+        double lambda = l; // initial guess
+        for (int iter = 0; iter < 20; iter++) {
+            double lambdaOrig = lambda;
+            cosLambda = Math.cos(lambda);
+            sinLambda = Math.sin(lambda);
+            double t1 = cosU2 * sinLambda;
+            double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
+            double sinSqSigma = t1 * t1 + t2 * t2;
+            sinSigma = Math.sqrt(sinSqSigma);
+            cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda;
+            sigma = Math.atan2(sinSigma, cosSigma);
+            double sinAlpha = (sinSigma == 0) ? 0.0 :
+                    cosU1cosU2 * sinLambda / sinSigma;
+            cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
+            cos2SM = (cosSqAlpha == 0) ? 0.0 : cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha;
+
+            double uSquared = cosSqAlpha * aSqMinusBSqOverBSq;
+            aA = 1 + (uSquared / 16384.0) * (4096.0 + uSquared * (-768 + uSquared * (320.0
+                    - 175.0 * uSquared)));
+            double bB = (uSquared / 1024.0) * (256.0 + uSquared * (-128.0 + uSquared * (74.0
+                    - 47.0 * uSquared)));
+            double cC = (f / 16.0) * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha));
+            double cos2SMSq = cos2SM * cos2SM;
+            deltaSigma = bB * sinSigma * (cos2SM + (bB / 4.0) * (cosSigma * (-1.0 + 2.0 * cos2SMSq)
+                    - (bB / 6.0) * cos2SM * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0
+                    + 4.0 * cos2SMSq)));
+
+            lambda = l + (1.0 - cC) * f * sinAlpha * (sigma + cC * sinSigma * (cos2SM
+                    + cC * cosSigma * (-1.0 + 2.0 * cos2SM * cos2SM)));
+
+            double delta = (lambda - lambdaOrig) / lambda;
+            if (Math.abs(delta) < 1.0e-12) {
+                break;
+            }
+        }
+
+        results.mDistance = (float) (b * aA * (sigma - deltaSigma));
+        float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
+                cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
+        initialBearing = (float) (initialBearing * (180.0 / Math.PI));
+        results.mInitialBearing = initialBearing;
+        float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
+                -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
+        finalBearing = (float) (finalBearing * (180.0 / Math.PI));
+        results.mFinalBearing = finalBearing;
+        results.mLat1 = lat1;
+        results.mLat2 = lat2;
+        results.mLon1 = lon1;
+        results.mLon2 = lon2;
+    }
+
+    /**
+     * Computes the approximate distance in meters between two
+     * locations, and optionally the initial and final bearings of the
+     * shortest path between them.  Distance and bearing are defined using the
+     * WGS84 ellipsoid.
+     *
+     * <p> The computed distance is stored in results[0].  If results has length
+     * 2 or greater, the initial bearing is stored in results[1]. If results has
+     * length 3 or greater, the final bearing is stored in results[2].
+     *
+     * @param startLatitude the starting latitude
+     * @param startLongitude the starting longitude
+     * @param endLatitude the ending latitude
+     * @param endLongitude the ending longitude
+     * @param results an array of floats to hold the results
+     *
+     * @throws IllegalArgumentException if results is null or has length < 1
+     */
+    public static void distanceBetween(
+            @FloatRange double startLatitude,
+            @FloatRange double startLongitude,
+            @FloatRange double endLatitude,
+            @FloatRange double endLongitude,
+            float[] results) {
+        if (results == null || results.length < 1) {
+            throw new IllegalArgumentException("results is null or has length < 1");
+        }
+        BearingDistanceCache cache = sBearingDistanceCache.get();
+        computeDistanceAndBearing(startLatitude, startLongitude,
+                endLatitude, endLongitude, cache);
+        results[0] = cache.mDistance;
+        if (results.length > 1) {
+            results[1] = cache.mInitialBearing;
+            if (results.length > 2) {
+                results[2] = cache.mFinalBearing;
+            }
+        }
+    }
+
     private static class BearingDistanceCache {
         double mLat1 = 0.0;
         double mLon1 = 0.0;
diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java
index 35a4091..031642b 100644
--- a/location/java/android/location/LocationListener.java
+++ b/location/java/android/location/LocationListener.java
@@ -38,9 +38,9 @@
 public interface LocationListener {
 
     /**
-     * Called when the location has changed. A wakelock is held on behalf on the listener for some
-     * brief amount of time as this callback executes. If this callback performs long running
-     * operations, it is the client's responsibility to obtain their own wakelock.
+     * Called when the location has changed. A wakelock may be held on behalf on the listener for
+     * some brief amount of time as this callback executes. If this callback performs long running
+     * operations, it is the client's responsibility to obtain their own wakelock if necessary.
      *
      * @param location the updated location
      */
@@ -48,7 +48,7 @@
 
     /**
      * Called when the location has changed and locations are being delivered in batches. The
-     * default implementation calls through to ({@link #onLocationChanged(Location)} with all
+     * default implementation calls through to {@link #onLocationChanged(Location)} with all
      * locations in the batch. The list of locations is always guaranteed to be non-empty, and is
      * always guaranteed to be ordered from earliest location to latest location (so that the
      * earliest location in the batch is at index 0 in the list, and the latest location in the
@@ -76,6 +76,11 @@
      * This callback will never be invoked on Android Q and above, and providers can be considered
      * as always in the {@link LocationProvider#AVAILABLE} state.
      *
+     * <p class="note">Note that this method only has a default implementation on Android R and
+     * above, and this method must still be overridden in order to run successfully on Android
+     * versions below R. LocationListenerCompat from the compat libraries may be used to avoid the
+     * need to override for older platforms.
+     *
      * @deprecated This callback will never be invoked on Android Q and above.
      */
     @Deprecated
@@ -84,6 +89,11 @@
     /**
      * Called when a provider this listener is registered with becomes enabled.
      *
+     * <p class="note">Note that this method only has a default implementation on Android R and
+     * above, and this method must still be overridden in order to run successfully on Android
+     * versions below R. LocationListenerCompat from the compat libraries may be used to avoid the
+     * need to override for older platforms.
+     *
      * @param provider the name of the location provider
      */
     default void onProviderEnabled(@NonNull String provider) {}
@@ -92,6 +102,11 @@
      * Called when the provider this listener is registered with becomes disabled. If a provider is
      * disabled when this listener is registered, this callback will be invoked immediately.
      *
+     * <p class="note">Note that this method only has a default implementation on Android R and
+     * above, and this method must still be overridden in order to run successfully on Android
+     * versions below R. LocationListenerCompat from the compat libraries may be used to avoid the
+     * need to override for older platforms.
+     *
      * @param provider the name of the location provider
      */
     default void onProviderDisabled(@NonNull String provider) {}
diff --git a/media/Android.bp b/media/Android.bp
index cf4a0b1..ce62b03 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -35,6 +35,7 @@
         "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
     ],
     imports: [
+        "android.media.audio.common.types",
         "android.media.soundtrigger.types",
         "media_permission-aidl",
     ],
@@ -45,20 +46,31 @@
     vendor_available: true,
     host_supported: true,
     double_loadable: true,
-    flags: ["-Werror", "-Weverything", ],
+    flags: [
+        "-Werror",
+        "-Weverything",
+    ],
     local_include_dir: "aidl",
     srcs: [
-        "aidl/android/media/audio/common/AudioChannelMask.aidl",
+        "aidl/android/media/audio/common/AudioChannelLayout.aidl",
         "aidl/android/media/audio/common/AudioConfig.aidl",
-        "aidl/android/media/audio/common/AudioFormat.aidl",
+        "aidl/android/media/audio/common/AudioConfigBase.aidl",
+        "aidl/android/media/audio/common/AudioEncapsulationMode.aidl",
+        "aidl/android/media/audio/common/AudioFormatDescription.aidl",
+        "aidl/android/media/audio/common/AudioFormatType.aidl",
         "aidl/android/media/audio/common/AudioOffloadInfo.aidl",
         "aidl/android/media/audio/common/AudioStreamType.aidl",
         "aidl/android/media/audio/common/AudioUsage.aidl",
+        "aidl/android/media/audio/common/PcmType.aidl",
     ],
     stability: "vintf",
     backend: {
         cpp: {
-            enabled: true,
+            min_sdk_version: "29",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media",
+            ],
         },
         java: {
             sdk_version: "module_current",
@@ -74,7 +86,10 @@
 aidl_interface {
     name: "android.media.soundtrigger.types",
     vendor_available: true,
-    flags: ["-Werror", "-Weverything", ],
+    flags: [
+        "-Werror",
+        "-Weverything",
+    ],
     local_include_dir: "aidl",
     srcs: [
         "aidl/android/media/soundtrigger/AudioCapabilities.aidl",
diff --git a/media/OWNERS b/media/OWNERS
index abfc8bf..0aff43e 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,8 +1,7 @@
-chz@google.com
+# Bug component: 1344
 elaurent@google.com
 essick@google.com
 etalvala@google.com
-gkasten@google.com
 hdmoon@google.com
 hkuang@google.com
 hunga@google.com
@@ -13,16 +12,13 @@
 jsharkey@android.com
 klhyun@google.com
 lajos@google.com
-marcone@google.com
 nchalko@google.com
 philburk@google.com
 quxiangfang@google.com
 wonsik@google.com
 
-# LON
-andrewlewis@google.com
-aquilescanta@google.com
-olly@google.com
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
 
 # SEO
 sungsoo@google.com
diff --git a/media/aidl/android/media/audio/common/AudioChannelLayout.aidl b/media/aidl/android/media/audio/common/AudioChannelLayout.aidl
new file mode 100644
index 0000000..311bd59
--- /dev/null
+++ b/media/aidl/android/media/audio/common/AudioChannelLayout.aidl
@@ -0,0 +1,243 @@
+/*
+ * 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.media.audio.common;
+
+/**
+ * This structure describes a layout of a multi-channel stream.
+ * There are two possible ways for representing a layout:
+ *
+ * - indexed mask, which tells what channels of an audio frame are used, but
+ *   doesn't label them in any way, thus a correspondence between channels in
+ *   the same position of frames originating from different streams must be
+ *   established externally;
+ *
+ * - layout mask, which gives a label to each channel, thus allowing to
+ *   match channels between streams of different layouts.
+ *
+ * Both representations are agnostic of the direction of audio transfer. Also,
+ * by construction, the number of bits set to '1' in the mask indicates the
+ * number of channels in the audio frame. A channel mask per se only defines the
+ * presence or absence of a channel, not the order. Please see 'INTERLEAVE_*'
+ * constants for the platform convention of order.
+ *
+ * The structure also defines a "voice mask" which is a special case of
+ * layout mask, intended for processing voice audio from telecommunication
+ * use cases.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+union AudioChannelLayout {
+    /**
+     * This variant is used for representing the "null" ("none") value
+     * for the channel layout. The field value must always be '0'.
+     */
+    int none = 0;
+    /**
+     * This variant is used for indicating an "invalid" layout for use by the
+     * framework only. HAL implementations must not accept or emit
+     * AudioChannelLayout values for this variant. The field value must always
+     * be '0'.
+     */
+    int invalid = 0;
+    /**
+     * This variant is used for representing indexed masks. The mask indicates
+     * what channels are used. For example, the mask that specifies to use only
+     * channels 1 and 3 when interacting with a multi-channel device is defined
+     * as a combination of the 1st and the 3rd bits and thus is equal to 5. See
+     * also the 'INDEX_MASK_*' constants. The 'indexMask' field must have at
+     * least one bit set.
+     */
+    int indexMask;
+    /**
+     * This variant is used for representing layout masks.
+     * It is recommended to use one of 'LAYOUT_*' values. The 'layoutMask' field
+     * must have at least one bit set.
+     */
+    int layoutMask;
+    /**
+     * This variant is used for processing of voice audio input and output.
+     * It is recommended to use one of 'VOICE_*' values. The 'voiceMask' field
+     * must have at least one bit set.
+     */
+    int voiceMask;
+
+    /**
+     * 'INDEX_MASK_*' constants define how many channels are used.
+     * The mask constants below are 'canonical' masks. Each 'INDEX_MASK_N'
+     * constant declares that all N channels are used and arranges
+     * them starting from the LSB.
+     */
+    const int INDEX_MASK_1 = (1 << 1) - 1;
+    const int INDEX_MASK_2 = (1 << 2) - 1;
+    const int INDEX_MASK_3 = (1 << 3) - 1;
+    const int INDEX_MASK_4 = (1 << 4) - 1;
+    const int INDEX_MASK_5 = (1 << 5) - 1;
+    const int INDEX_MASK_6 = (1 << 6) - 1;
+    const int INDEX_MASK_7 = (1 << 7) - 1;
+    const int INDEX_MASK_8 = (1 << 8) - 1;
+    const int INDEX_MASK_9 = (1 << 9) - 1;
+    const int INDEX_MASK_10 = (1 << 10) - 1;
+    const int INDEX_MASK_11 = (1 << 11) - 1;
+    const int INDEX_MASK_12 = (1 << 12) - 1;
+    const int INDEX_MASK_13 = (1 << 13) - 1;
+    const int INDEX_MASK_14 = (1 << 14) - 1;
+    const int INDEX_MASK_15 = (1 << 15) - 1;
+    const int INDEX_MASK_16 = (1 << 16) - 1;
+    const int INDEX_MASK_17 = (1 << 17) - 1;
+    const int INDEX_MASK_18 = (1 << 18) - 1;
+    const int INDEX_MASK_19 = (1 << 19) - 1;
+    const int INDEX_MASK_20 = (1 << 20) - 1;
+    const int INDEX_MASK_21 = (1 << 21) - 1;
+    const int INDEX_MASK_22 = (1 << 22) - 1;
+    const int INDEX_MASK_23 = (1 << 23) - 1;
+    const int INDEX_MASK_24 = (1 << 24) - 1;
+
+    /**
+     * 'LAYOUT_*' constants define channel layouts recognized by
+     * the audio system. The order of the channels in the frame is assumed
+     * to be from the LSB to MSB for all the bits set to '1'.
+     */
+    const int LAYOUT_MONO = CHANNEL_FRONT_LEFT;
+    const int LAYOUT_STEREO = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT;
+    const int LAYOUT_2POINT1 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_LOW_FREQUENCY;
+    const int LAYOUT_TRI = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER;
+    const int LAYOUT_TRI_BACK = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_BACK_CENTER;
+    const int LAYOUT_3POINT1 =
+            CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY;
+    const int LAYOUT_2POINT0POINT2 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT
+            | CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+    const int LAYOUT_2POINT1POINT2 = LAYOUT_2POINT0POINT2 | CHANNEL_LOW_FREQUENCY;
+    const int LAYOUT_3POINT0POINT2 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER
+            | CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+    const int LAYOUT_3POINT1POINT2 = LAYOUT_3POINT0POINT2 | CHANNEL_LOW_FREQUENCY;
+    const int LAYOUT_QUAD =
+            CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT;
+    const int LAYOUT_QUAD_SIDE =
+            CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
+    const int LAYOUT_SURROUND =
+            CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER;
+    const int LAYOUT_PENTA = LAYOUT_QUAD | CHANNEL_FRONT_CENTER;
+    const int LAYOUT_5POINT1 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER
+            | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT;
+    const int LAYOUT_5POINT1_SIDE = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER
+            | CHANNEL_LOW_FREQUENCY | CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
+    const int LAYOUT_5POINT1POINT2 =
+            LAYOUT_5POINT1 | CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+    const int LAYOUT_5POINT1POINT4 = LAYOUT_5POINT1 | CHANNEL_TOP_FRONT_LEFT
+            | CHANNEL_TOP_FRONT_RIGHT | CHANNEL_TOP_BACK_LEFT | CHANNEL_TOP_BACK_RIGHT;
+    const int LAYOUT_6POINT1 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER
+            | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT | CHANNEL_BACK_CENTER;
+    const int LAYOUT_7POINT1 = LAYOUT_5POINT1 | CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
+    const int LAYOUT_7POINT1POINT2 =
+            LAYOUT_7POINT1 | CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+    const int LAYOUT_7POINT1POINT4 = LAYOUT_7POINT1 | CHANNEL_TOP_FRONT_LEFT
+            | CHANNEL_TOP_FRONT_RIGHT | CHANNEL_TOP_BACK_LEFT | CHANNEL_TOP_BACK_RIGHT;
+    const int LAYOUT_9POINT1POINT4 =
+            LAYOUT_7POINT1POINT4 | CHANNEL_FRONT_WIDE_LEFT | CHANNEL_FRONT_WIDE_RIGHT;
+    const int LAYOUT_9POINT1POINT6 =
+            LAYOUT_9POINT1POINT4 | CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+    const int LAYOUT_13POINT_360RA = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER
+            | CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT | CHANNEL_TOP_FRONT_LEFT
+            | CHANNEL_TOP_FRONT_RIGHT | CHANNEL_TOP_FRONT_CENTER | CHANNEL_TOP_BACK_LEFT
+            | CHANNEL_TOP_BACK_RIGHT | CHANNEL_BOTTOM_FRONT_LEFT | CHANNEL_BOTTOM_FRONT_RIGHT
+            | CHANNEL_BOTTOM_FRONT_CENTER;
+    const int LAYOUT_22POINT2 = LAYOUT_7POINT1POINT4 | CHANNEL_FRONT_LEFT_OF_CENTER
+            | CHANNEL_FRONT_RIGHT_OF_CENTER | CHANNEL_BACK_CENTER | CHANNEL_TOP_CENTER
+            | CHANNEL_TOP_FRONT_CENTER | CHANNEL_TOP_BACK_CENTER | CHANNEL_TOP_SIDE_LEFT
+            | CHANNEL_TOP_SIDE_RIGHT | CHANNEL_BOTTOM_FRONT_LEFT | CHANNEL_BOTTOM_FRONT_RIGHT
+            | CHANNEL_BOTTOM_FRONT_CENTER | CHANNEL_LOW_FREQUENCY_2;
+    const int LAYOUT_MONO_HAPTIC_A = LAYOUT_MONO | CHANNEL_HAPTIC_A;
+    const int LAYOUT_STEREO_HAPTIC_A = LAYOUT_STEREO | CHANNEL_HAPTIC_A;
+    const int LAYOUT_HAPTIC_AB = CHANNEL_HAPTIC_A | CHANNEL_HAPTIC_B;
+    const int LAYOUT_MONO_HAPTIC_AB = LAYOUT_MONO | LAYOUT_HAPTIC_AB;
+    const int LAYOUT_STEREO_HAPTIC_AB = LAYOUT_STEREO | LAYOUT_HAPTIC_AB;
+    const int LAYOUT_FRONT_BACK = CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER;
+
+    /**
+     * Expresses the convention when stereo audio samples are stored interleaved
+     * in an array.  This should improve readability by allowing code to use
+     * symbolic indices instead of hard-coded [0] and [1].
+     *
+     * For multi-channel beyond stereo, the platform convention is that channels
+     * are interleaved in order from least significant channel mask bit to most
+     * significant channel mask bit, with unused bits skipped. Any exceptions
+     * to this convention will be noted at the appropriate API.
+     */
+    const int INTERLEAVE_LEFT = 0;
+    const int INTERLEAVE_RIGHT = 1;
+
+    /**
+     * 'CHANNEL_*' constants are used to build 'LAYOUT_*' masks. Each constant
+     * must have exactly one bit set. The values do not match
+     * 'android.media.AudioFormat.CHANNEL_OUT_*' constants from the SDK
+     * for better efficiency in masks processing.
+     */
+    const int CHANNEL_FRONT_LEFT = 1 << 0;
+    const int CHANNEL_FRONT_RIGHT = 1 << 1;
+    const int CHANNEL_FRONT_CENTER = 1 << 2;
+    const int CHANNEL_LOW_FREQUENCY = 1 << 3;
+    const int CHANNEL_BACK_LEFT = 1 << 4;
+    const int CHANNEL_BACK_RIGHT = 1 << 5;
+    const int CHANNEL_FRONT_LEFT_OF_CENTER = 1 << 6;
+    const int CHANNEL_FRONT_RIGHT_OF_CENTER = 1 << 7;
+    const int CHANNEL_BACK_CENTER = 1 << 8;
+    const int CHANNEL_SIDE_LEFT = 1 << 9;
+    const int CHANNEL_SIDE_RIGHT = 1 << 10;
+    const int CHANNEL_TOP_CENTER = 1 << 11;
+    const int CHANNEL_TOP_FRONT_LEFT = 1 << 12;
+    const int CHANNEL_TOP_FRONT_CENTER = 1 << 13;
+    const int CHANNEL_TOP_FRONT_RIGHT = 1 << 14;
+    const int CHANNEL_TOP_BACK_LEFT = 1 << 15;
+    const int CHANNEL_TOP_BACK_CENTER = 1 << 16;
+    const int CHANNEL_TOP_BACK_RIGHT = 1 << 17;
+    const int CHANNEL_TOP_SIDE_LEFT = 1 << 18;
+    const int CHANNEL_TOP_SIDE_RIGHT = 1 << 19;
+    const int CHANNEL_BOTTOM_FRONT_LEFT = 1 << 20;
+    const int CHANNEL_BOTTOM_FRONT_CENTER = 1 << 21;
+    const int CHANNEL_BOTTOM_FRONT_RIGHT = 1 << 22;
+    const int CHANNEL_LOW_FREQUENCY_2 = 1 << 23;
+    const int CHANNEL_FRONT_WIDE_LEFT = 1 << 24;
+    const int CHANNEL_FRONT_WIDE_RIGHT = 1 << 25;
+    /**
+     * Haptic channels are not part of multichannel standards, however they
+     * enhance user experience when playing so they are packed together with the
+     * channels of the program. To avoid collision with positional channels the
+     * values for haptic channels start at the MSB of an integer (after the sign
+     * bit) and move down to LSB.
+     */
+    const int CHANNEL_HAPTIC_B = 1 << 29;
+    const int CHANNEL_HAPTIC_A = 1 << 30;
+
+    /**
+     * 'VOICE_*' constants define layouts for voice audio. The order of the
+     * channels in the frame is assumed to be from the LSB to MSB for all the
+     * bits set to '1'.
+     */
+    const int VOICE_UPLINK_MONO = CHANNEL_VOICE_UPLINK;
+    const int VOICE_DNLINK_MONO = CHANNEL_VOICE_DNLINK;
+    const int VOICE_CALL_MONO = CHANNEL_VOICE_UPLINK | CHANNEL_VOICE_DNLINK;
+
+    /**
+     * 'CHANNEL_VOICE_*' constants are used to build 'VOICE_*' masks. Each
+     * constant must have exactly one bit set. Use the same values as
+     * 'android.media.AudioFormat.CHANNEL_IN_VOICE_*' constants from the SDK.
+     */
+    const int CHANNEL_VOICE_UPLINK = 0x4000;
+    const int CHANNEL_VOICE_DNLINK = 0x8000;
+}
diff --git a/media/aidl/android/media/audio/common/AudioChannelMask.aidl b/media/aidl/android/media/audio/common/AudioChannelMask.aidl
deleted file mode 100644
index 17be8dd..0000000
--- a/media/aidl/android/media/audio/common/AudioChannelMask.aidl
+++ /dev/null
@@ -1,221 +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.
- */
-
- // This file has been semi-automatically generated using hidl2aidl from its counterpart in
- // hardware/interfaces/audio/common/5.0/types.hal
-
-package android.media.audio.common;
-
-/**
- * A channel mask per se only defines the presence or absence of a channel, not
- * the order.
- *
- * The channel order convention is that channels are interleaved in order from
- * least significant channel mask bit to most significant channel mask bit,
- * with unused bits skipped. For example for stereo, LEFT would be first,
- * followed by RIGHT.
- * Any exceptions to this convention are noted at the appropriate API.
- *
- * AudioChannelMask is an opaque type and its internal layout should not be
- * assumed as it may change in the future.  Instead, always use functions
- * to examine it.
- *
- * These are the current representations:
- *
- *   REPRESENTATION_POSITION
- *     is a channel mask representation for position assignment.  Each low-order
- *     bit corresponds to the spatial position of a transducer (output), or
- *     interpretation of channel (input).  The user of a channel mask needs to
- *     know the context of whether it is for output or input.  The constants
- *     OUT_* or IN_* apply to the bits portion.  It is not permitted for no bits
- *     to be set.
- *
- *   REPRESENTATION_INDEX
- *     is a channel mask representation for index assignment.  Each low-order
- *     bit corresponds to a selected channel.  There is no platform
- *     interpretation of the various bits.  There is no concept of output or
- *     input.  It is not permitted for no bits to be set.
- *
- * All other representations are reserved for future use.
- *
- * Warning: current representation distinguishes between input and output, but
- * this will not the be case in future revisions of the platform. Wherever there
- * is an ambiguity between input and output that is currently resolved by
- * checking the channel mask, the implementer should look for ways to fix it
- * with additional information outside of the mask.
- *
- * TODO: this should be replaced with strings or other mechanisms that are easy to extend, in line
- *     with the audio HAL conventions.
- * {@hide}
- */
-@VintfStability
-@Backing(type="int")
-enum AudioChannelMask {
-    /**
-     * must be 0 for compatibility
-     */
-    REPRESENTATION_POSITION = 0,
-    /**
-     * 1 is reserved for future use
-     */
-    REPRESENTATION_INDEX = 2,
-    /**
-     * 3 is reserved for future use
-     *
-     *
-     * These can be a complete value of AudioChannelMask
-     */
-    NONE = 0x0,
-    INVALID = 0xC0000000,
-    /**
-     * These can be the bits portion of an AudioChannelMask
-     * with representation REPRESENTATION_POSITION.
-     *
-     *
-     * output channels
-     */
-    OUT_FRONT_LEFT = 0x1,
-    OUT_FRONT_RIGHT = 0x2,
-    OUT_FRONT_CENTER = 0x4,
-    OUT_LOW_FREQUENCY = 0x8,
-    OUT_BACK_LEFT = 0x10,
-    OUT_BACK_RIGHT = 0x20,
-    OUT_FRONT_LEFT_OF_CENTER = 0x40,
-    OUT_FRONT_RIGHT_OF_CENTER = 0x80,
-    OUT_BACK_CENTER = 0x100,
-    OUT_SIDE_LEFT = 0x200,
-    OUT_SIDE_RIGHT = 0x400,
-    OUT_TOP_CENTER = 0x800,
-    OUT_TOP_FRONT_LEFT = 0x1000,
-    OUT_TOP_FRONT_CENTER = 0x2000,
-    OUT_TOP_FRONT_RIGHT = 0x4000,
-    OUT_TOP_BACK_LEFT = 0x8000,
-    OUT_TOP_BACK_CENTER = 0x10000,
-    OUT_TOP_BACK_RIGHT = 0x20000,
-    OUT_TOP_SIDE_LEFT = 0x40000,
-    OUT_TOP_SIDE_RIGHT = 0x80000,
-    /**
-     * Haptic channel characteristics are specific to a device and
-     * only used to play device specific resources (eg: ringtones).
-     * The HAL can freely map A and B to haptic controllers, the
-     * framework shall not interpret those values and forward them
-     * from the device audio assets.
-     */
-    OUT_HAPTIC_A = 0x20000000,
-    OUT_HAPTIC_B = 0x10000000,
-
-    OUT_MONO = OUT_FRONT_LEFT,
-    OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
-    OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
-    OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY),
-    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY),
-    OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_BACK_LEFT | OUT_BACK_RIGHT),
-    OUT_QUAD_BACK = OUT_QUAD,
-    /**
-     * like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_*
-     */
-    OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_BACK_CENTER),
-    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
-    OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT),
-    OUT_5POINT1_BACK = OUT_5POINT1,
-    /**
-     * like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_*
-     */
-    OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-    OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-    OUT_5POINT1POINT4 = (OUT_5POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
-    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_BACK_CENTER),
-    /**
-     * matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
-     */
-    OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-    OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-    OUT_7POINT1POINT4 = (OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
-    OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
-    OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
-    OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
-    OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
-    OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A | OUT_HAPTIC_B),
-
-    /**
-     * These are bits only, not complete values
-     *
-     *
-     * input channels
-     */
-    IN_LEFT = 0x4,
-    IN_RIGHT = 0x8,
-    IN_FRONT = 0x10,
-    IN_BACK = 0x20,
-    IN_LEFT_PROCESSED = 0x40,
-    IN_RIGHT_PROCESSED = 0x80,
-    IN_FRONT_PROCESSED = 0x100,
-    IN_BACK_PROCESSED = 0x200,
-    IN_PRESSURE = 0x400,
-    IN_X_AXIS = 0x800,
-    IN_Y_AXIS = 0x1000,
-    IN_Z_AXIS = 0x2000,
-    IN_BACK_LEFT = 0x10000,
-    IN_BACK_RIGHT = 0x20000,
-    IN_CENTER = 0x40000,
-    IN_LOW_FREQUENCY = 0x100000,
-    IN_TOP_LEFT = 0x200000,
-    IN_TOP_RIGHT = 0x400000,
-    IN_VOICE_UPLINK = 0x4000,
-    IN_VOICE_DNLINK = 0x8000,
-// TODO(ytai): Aliases not currently supported in AIDL - can inline the values.
-//    IN_MONO = IN_FRONT,
-//    IN_STEREO = (IN_LEFT | IN_RIGHT),
-//    IN_FRONT_BACK = (IN_FRONT | IN_BACK),
-//    IN_6 = (IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK | IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
-//    IN_2POINT0POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
-//    IN_2POINT1POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY),
-//    IN_3POINT0POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
-//    IN_3POINT1POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY),
-//    IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY),
-//    IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
-//    IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
-//    IN_VOICE_CALL_MONO = (IN_VOICE_UPLINK_MONO | IN_VOICE_DNLINK_MONO),
-//    COUNT_MAX = 30,
-//    INDEX_HDR = REPRESENTATION_INDEX << COUNT_MAX,
-//    INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
-//    INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
-//    INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
-//    INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
-//    INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
-//    INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
-//    INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
-//    INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1),
-//    INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1),
-//    INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1),
-//    INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1),
-//    INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1),
-//    INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1),
-//    INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1),
-//    INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1),
-//    INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1),
-//    INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1),
-//    INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1),
-//    INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1),
-//    INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1),
-//    INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1),
-//    INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1),
-//    INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1),
-//    INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1),
-}
diff --git a/media/aidl/android/media/audio/common/AudioConfig.aidl b/media/aidl/android/media/audio/common/AudioConfig.aidl
index d128561..ce2da4f 100644
--- a/media/aidl/android/media/audio/common/AudioConfig.aidl
+++ b/media/aidl/android/media/audio/common/AudioConfig.aidl
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
- // This file has been semi-automatically generated using hidl2aidl from its counterpart in
- // hardware/interfaces/audio/common/5.0/types.hal
-
 package android.media.audio.common;
 
-import android.media.audio.common.AudioFormat;
+import android.media.audio.common.AudioConfigBase;
 import android.media.audio.common.AudioOffloadInfo;
 
 /**
@@ -27,12 +24,11 @@
  *
  * {@hide}
  */
-@JavaDerive(equals = true, toString = true)
+@JavaDerive(equals=true, toString=true)
 @VintfStability
 parcelable AudioConfig {
-    int sampleRateHz;
-    int channelMask;
-    AudioFormat format = AudioFormat.INVALID;
+    AudioConfigBase base;
     AudioOffloadInfo offloadInfo;
+    /** I/O buffer size in frames. */
     long frameCount;
 }
diff --git a/media/aidl/android/media/audio/common/AudioConfigBase.aidl b/media/aidl/android/media/audio/common/AudioConfigBase.aidl
new file mode 100644
index 0000000..5210d0d
--- /dev/null
+++ b/media/aidl/android/media/audio/common/AudioConfigBase.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.audio.common;
+
+import android.media.audio.common.AudioChannelLayout;
+import android.media.audio.common.AudioFormatDescription;
+
+/**
+ * Base configuration attributes applicable to any stream of audio.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioConfigBase {
+    int sampleRate;
+    AudioChannelLayout channelMask;
+    AudioFormatDescription format;
+}
diff --git a/media/aidl/android/media/audio/common/AudioEncapsulationMode.aidl b/media/aidl/android/media/audio/common/AudioEncapsulationMode.aidl
new file mode 100644
index 0000000..6f8e9e1
--- /dev/null
+++ b/media/aidl/android/media/audio/common/AudioEncapsulationMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.audio.common;
+
+/**
+ * Encapsulation mode used for sending audio compressed data.
+ *
+ * {@hide}
+ */
+@VintfStability
+@Backing(type="byte")
+enum AudioEncapsulationMode {
+    /**
+     * Used as default value in parcelables to indicate that a value was not
+     * set. Should never be considered a valid setting, except for backward
+     * compatibility scenarios.
+     */
+    INVALID = -1,
+    /** No encapsulation mode for metadata. */
+    NONE = 0,
+    /** Elementary stream payload with metadata. */
+    ELEMENTARY_STREAM = 1,
+    /** Handle-based payload with metadata. */
+    HANDLE = 2,
+}
diff --git a/media/aidl/android/media/audio/common/AudioFormat.aidl b/media/aidl/android/media/audio/common/AudioFormat.aidl
deleted file mode 100644
index 73fbca2..0000000
--- a/media/aidl/android/media/audio/common/AudioFormat.aidl
+++ /dev/null
@@ -1,171 +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.
- */
-
- // This file has been semi-automatically generated using hidl2aidl from its counterpart in
- // hardware/interfaces/audio/common/5.0/types.hal
-
-package android.media.audio.common;
-
-/**
- * Audio format  is a 32-bit word that consists of:
- *   main format field (upper 8 bits)
- *   sub format field (lower 24 bits).
- *
- * The main format indicates the main codec type. The sub format field indicates
- * options and parameters for each format. The sub format is mainly used for
- * record to indicate for instance the requested bitrate or profile.  It can
- * also be used for certain formats to give informations not present in the
- * encoded audio stream (e.g. octet alignement for AMR).
- *
- * {@hide}
- */
-@VintfStability
-@Backing(type="int")
-enum AudioFormat {
-   INVALID = 0xFFFFFFFF,
-   DEFAULT = 0,
-   PCM = 0x00000000,
-   MP3 = 0x01000000,
-   AMR_NB = 0x02000000,
-   AMR_WB = 0x03000000,
-   AAC = 0x04000000,
-   /**
-    * Deprecated, Use AAC_HE_V1
-    */
-   HE_AAC_V1 = 0x05000000,
-   /**
-    * Deprecated, Use AAC_HE_V2
-    */
-   HE_AAC_V2 = 0x06000000,
-   VORBIS = 0x07000000,
-   OPUS = 0x08000000,
-   AC3 = 0x09000000,
-   E_AC3 = 0x0A000000,
-   DTS = 0x0B000000,
-   DTS_HD = 0x0C000000,
-   /**
-    * IEC61937 is encoded audio wrapped in 16-bit PCM.
-    */
-   IEC61937 = 0x0D000000,
-   DOLBY_TRUEHD = 0x0E000000,
-   EVRC = 0x10000000,
-   EVRCB = 0x11000000,
-   EVRCWB = 0x12000000,
-   EVRCNW = 0x13000000,
-   AAC_ADIF = 0x14000000,
-   WMA = 0x15000000,
-   WMA_PRO = 0x16000000,
-   AMR_WB_PLUS = 0x17000000,
-   MP2 = 0x18000000,
-   QCELP = 0x19000000,
-   DSD = 0x1A000000,
-   FLAC = 0x1B000000,
-   ALAC = 0x1C000000,
-   APE = 0x1D000000,
-   AAC_ADTS = 0x1E000000,
-   SBC = 0x1F000000,
-   APTX = 0x20000000,
-   APTX_HD = 0x21000000,
-   AC4 = 0x22000000,
-   LDAC = 0x23000000,
-   /**
-    * Dolby Metadata-enhanced Audio Transmission
-    */
-   MAT = 0x24000000,
-   AAC_LATM = 0x25000000,
-   CELT = 0x26000000,
-   APTX_ADAPTIVE = 0x27000000,
-   LHDC = 0x28000000,
-   LHDC_LL = 0x29000000,
-   APTX_TWSP = 0x2A000000,
-   /**
-    * Deprecated
-    */
-   MAIN_MASK = 0xFF000000,
-   SUB_MASK = 0x00FFFFFF,
-   /**
-    * Subformats
-    */
-   PCM_SUB_16_BIT = 0x1,
-   PCM_SUB_8_BIT = 0x2,
-   PCM_SUB_32_BIT = 0x3,
-   PCM_SUB_8_24_BIT = 0x4,
-   PCM_SUB_FLOAT = 0x5,
-   PCM_SUB_24_BIT_PACKED = 0x6,
-   MP3_SUB_NONE = 0x0,
-   AMR_SUB_NONE = 0x0,
-   AAC_SUB_MAIN = 0x1,
-   AAC_SUB_LC = 0x2,
-   AAC_SUB_SSR = 0x4,
-   AAC_SUB_LTP = 0x8,
-   AAC_SUB_HE_V1 = 0x10,
-   AAC_SUB_SCALABLE = 0x20,
-   AAC_SUB_ERLC = 0x40,
-   AAC_SUB_LD = 0x80,
-   AAC_SUB_HE_V2 = 0x100,
-   AAC_SUB_ELD = 0x200,
-   AAC_SUB_XHE = 0x300,
-   VORBIS_SUB_NONE = 0x0,
-   E_AC3_SUB_JOC = 0x1,
-   MAT_SUB_1_0 = 0x1,
-   MAT_SUB_2_0 = 0x2,
-   MAT_SUB_2_1 = 0x3,
-// TODO(ytai): Aliases not currently supported in AIDL - can inline the values.
-//   /**
-//    * Aliases
-//    *
-//    *
-//    * note != AudioFormat.ENCODING_PCM_16BIT
-//    */
-//   PCM_16_BIT = (PCM | PCM_SUB_16_BIT),
-//   /**
-//    * note != AudioFormat.ENCODING_PCM_8BIT
-//    */
-//   PCM_8_BIT = (PCM | PCM_SUB_8_BIT),
-//   PCM_32_BIT = (PCM | PCM_SUB_32_BIT),
-//   PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT),
-//   PCM_FLOAT = (PCM | PCM_SUB_FLOAT),
-//   PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED),
-//   AAC_MAIN = (AAC | AAC_SUB_MAIN),
-//   AAC_LC = (AAC | AAC_SUB_LC),
-//   AAC_SSR = (AAC | AAC_SUB_SSR),
-//   AAC_LTP = (AAC | AAC_SUB_LTP),
-//   AAC_HE_V1 = (AAC | AAC_SUB_HE_V1),
-//   AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE),
-//   AAC_ERLC = (AAC | AAC_SUB_ERLC),
-//   AAC_LD = (AAC | AAC_SUB_LD),
-//   AAC_HE_V2 = (AAC | AAC_SUB_HE_V2),
-//   AAC_ELD = (AAC | AAC_SUB_ELD),
-//   AAC_XHE = (AAC | AAC_SUB_XHE),
-//   AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN),
-//   AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC),
-//   AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR),
-//   AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP),
-//   AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1),
-//   AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE),
-//   AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC),
-//   AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD),
-//   AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2),
-//   AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD),
-//   AAC_ADTS_XHE = (AAC_ADTS | AAC_SUB_XHE),
-//   E_AC3_JOC = (E_AC3 | E_AC3_SUB_JOC),
-//   MAT_1_0 = (MAT | MAT_SUB_1_0),
-//   MAT_2_0 = (MAT | MAT_SUB_2_0),
-//   MAT_2_1 = (MAT | MAT_SUB_2_1),
-//   AAC_LATM_LC = (AAC_LATM | AAC_SUB_LC),
-//   AAC_LATM_HE_V1 = (AAC_LATM | AAC_SUB_HE_V1),
-//   AAC_LATM_HE_V2 = (AAC_LATM | AAC_SUB_HE_V2),
-}
diff --git a/media/aidl/android/media/audio/common/AudioFormatDescription.aidl b/media/aidl/android/media/audio/common/AudioFormatDescription.aidl
new file mode 100644
index 0000000..57f2bdb
--- /dev/null
+++ b/media/aidl/android/media/audio/common/AudioFormatDescription.aidl
@@ -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 android.media.audio.common;
+
+import android.media.audio.common.AudioFormatType;
+import android.media.audio.common.PcmType;
+
+/**
+ * An extensible type for specifying audio formats. All formats are largely
+ * divided into two classes: PCM and non-PCM (bitstreams). Bitstreams can
+ * be encapsulated into PCM streams.
+ *
+ * The type defined in a way to make each format uniquely identifiable, so
+ * that if the framework and the HAL construct a value for the same type
+ * (e.g. PCM 16 bit), they will produce identical parcelables which will have
+ * identical hashes. This makes possible deduplicating type descriptions
+ * by the framework when they are received from different HAL modules without
+ * relying on having some centralized registry of enumeration values.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioFormatDescription {
+    /**
+     * The type of the audio format. See the 'AudioFormatType' for the
+     * list of supported values.
+     */
+    AudioFormatType type = AudioFormatType.DEFAULT;
+    /**
+     * The type of the PCM stream or the transport stream for PCM
+     * encapsulations.  See 'PcmType' for the list of supported values.
+     */
+    PcmType pcm = PcmType.DEFAULT;
+    /**
+     * Optional encoding specification. Must be left empty when:
+     *
+     *  - 'type == DEFAULT && pcm == DEFAULT' -- that means "default" type;
+     *  - 'type == PCM' -- that means a regular PCM stream (not an encapsulation
+     *    of an encoded bitstream).
+     *
+     * For PCM encapsulations of encoded bitstreams (e.g. an encapsulation
+     * according to IEC-61937 standard), the value of the 'pcm' field must
+     * be set accordingly, as an example, PCM_INT_16_BIT must be used for
+     * IEC-61937. Note that 'type == NON_PCM' in this case.
+     *
+     * Encoding names mostly follow IANA standards for media types (MIME), and
+     * frameworks/av/media/libstagefright/foundation/MediaDefs.cpp with the
+     * latter having priority.  Since there are still many audio types not found
+     * in any of these lists, the following rules are applied:
+     *
+     *   - If there is a direct MIME type for the encoding, the MIME type name
+     *     is used as is, e.g. "audio/eac3" for the EAC-3 format.
+     *   - If the encoding is a "subformat" of a MIME-registered format,
+     *     the latter is augmented with a suffix, e.g. "audio/eac3-joc" for the
+     *     JOC extension of EAC-3.
+     *   - If it's a proprietary format, a "vnd." prefix is added, similar to
+     *     IANA rules, e.g. "audio/vnd.dolby.truehd".
+     *   - Otherwise, "x-" prefix is added, e.g. "audio/x-iec61937".
+     *   - All MIME types not found in the IANA formats list have an associated
+     *     comment.
+     */
+    @utf8InCpp String encoding;
+}
diff --git a/media/aidl/android/media/audio/common/AudioFormatType.aidl b/media/aidl/android/media/audio/common/AudioFormatType.aidl
new file mode 100644
index 0000000..1759401
--- /dev/null
+++ b/media/aidl/android/media/audio/common/AudioFormatType.aidl
@@ -0,0 +1,49 @@
+/*
+ * 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.media.audio.common;
+
+/**
+ * The type of the audio format. Only used as part of 'AudioFormatDescription'
+ * structure.
+ */
+@VintfStability
+@Backing(type="byte")
+enum AudioFormatType {
+    /**
+     * "Default" type is used when the client does not care about the actual
+     * format. All fields of 'AudioFormatDescription' must have default / empty
+     * / null values.
+     */
+    DEFAULT = 0,
+    /**
+     * When the 'encoding' field of 'AudioFormatDescription' is not empty, it
+     * specifies the codec used for bitstream (non-PCM) data. It is also used
+     * in the case when the bitstream data is encapsulated into a PCM stream,
+     * see the documentation for 'AudioFormatDescription'.
+     */
+    NON_PCM = DEFAULT,
+    /**
+     * PCM type. The 'pcm' field of 'AudioFormatDescription' is used to specify
+     * the actual sample size and representation.
+     */
+    PCM = 1,
+    /**
+     * Value reserved for system use only. HALs must never return this value to
+     * the system or accept it from the system.
+     */
+    SYS_RESERVED_INVALID = -1,
+}
diff --git a/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
index 7be5e6a..d8da065 100644
--- a/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
+++ b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
@@ -14,12 +14,10 @@
  * limitations under the License.
  */
 
- // This file has been semi-automatically generated using hidl2aidl from its counterpart in
- // hardware/interfaces/audio/common/5.0/types.hal
-
 package android.media.audio.common;
 
-import android.media.audio.common.AudioFormat;
+import android.media.audio.common.AudioConfigBase;
+import android.media.audio.common.AudioEncapsulationMode;
 import android.media.audio.common.AudioStreamType;
 import android.media.audio.common.AudioUsage;
 
@@ -28,19 +26,31 @@
  *
  * {@hide}
  */
-@JavaDerive(equals = true, toString = true)
+@JavaDerive(equals=true, toString=true)
 @VintfStability
 parcelable AudioOffloadInfo {
-    int sampleRateHz;
-    int channelMask;
-    AudioFormat format = AudioFormat.INVALID;
+    /** Base audio configuration. */
+    AudioConfigBase base;
+    /** Stream type. Intended for use by the system only. */
     AudioStreamType streamType = AudioStreamType.INVALID;
+    /** Bit rate in bits per second. */
     int bitRatePerSecond;
-    long durationMicroseconds;
+    /** Duration in microseconds, -1 if unknown. */
+    long durationUs;
+    /** True if the stream is tied to a video stream. */
     boolean hasVideo;
+    /** True if streaming, false if local playback. */
     boolean isStreaming;
-    int bitWidth;
-    int bufferSize;
+    /** Sample bit width. */
+    int bitWidth = 16;
+    /** Offload fragment size. */
+    int offloadBufferSize;
+    /** See the documentation of AudioUsage. */
     AudioUsage usage = AudioUsage.INVALID;
+    /** See the documentation of AudioEncapsulationMode. */
+    AudioEncapsulationMode encapsulationMode = AudioEncapsulationMode.INVALID;
+    /** Content id from tuner HAL (0 if none). */
+    int contentId;
+    /** Sync id from tuner HAL (0 if none). */
+    int syncId;
 }
-
diff --git a/media/aidl/android/media/audio/common/AudioStreamType.aidl b/media/aidl/android/media/audio/common/AudioStreamType.aidl
index 8b70367..1fa3a9c 100644
--- a/media/aidl/android/media/audio/common/AudioStreamType.aidl
+++ b/media/aidl/android/media/audio/common/AudioStreamType.aidl
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
- // This file has been semi-automatically generated using hidl2aidl from its counterpart in
- // hardware/interfaces/audio/common/5.0/types.hal
-
 package android.media.audio.common;
 
 /**
- *  Audio streams
- *
- * Audio stream type describing the intended use case of a stream.
+ * Audio stream type describing the intended use case of a stream. Streams
+ * must be used in the context of volume management only. For playback type
+ * identification purposes, AudioContentType and AudioUsage must be used,
+ * similar to how it's done in the SDK.
  *
  * {@hide}
  */
@@ -30,21 +28,71 @@
 @Backing(type="int")
 enum AudioStreamType {
     /**
-     * Used as default value in parcelables to indicate that a value was not set.
-     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     * Used as default value in parcelables to indicate that a value was not
+     * set. Should never be considered a valid setting, except for backward
+     * compatibility scenarios.
      */
     INVALID = -2,
+    /**
+     * Indicates that the operation is applied to the "default" stream
+     * in this context, e.g. MUSIC in normal device state, or RING if the
+     * phone is ringing.
+     */
     DEFAULT = -1,
-    MIN = 0,
+    /** Used to identify the volume of audio streams for phone calls. */
     VOICE_CALL = 0,
+    /** Used to identify the volume of audio streams for system sounds. */
     SYSTEM = 1,
+    /**
+     * Used to identify the volume of audio streams for the phone ring and
+     * message alerts.
+     */
     RING = 2,
+    /** Used to identify the volume of audio streams for music playback. */
     MUSIC = 3,
+    /** Used to identify the volume of audio streams for alarms. */
     ALARM = 4,
+    /** Used to identify the volume of audio streams for notifications. */
     NOTIFICATION = 5,
+    /**
+     * Used to identify the volume of audio streams for phone calls when
+     * connected via Bluetooth.
+     */
     BLUETOOTH_SCO = 6,
+    /**
+     * Used to identify the volume of audio streams for enforced system sounds
+     * in certain countries (e.g camera in Japan).
+     */
     ENFORCED_AUDIBLE = 7,
+    /** Used to identify the volume of audio streams for DTMF tones. */
     DTMF = 8,
+    /**
+     * Used to identify the volume of audio streams exclusively transmitted
+     * through the speaker (TTS) of the device.
+     */
     TTS = 9,
+    /**
+     * Used to identify the volume of audio streams for accessibility prompts.
+     */
     ACCESSIBILITY = 10,
+    /**
+     * Used to identify the volume of audio streams for virtual assistant.
+     */
+    ASSISTANT = 11,
+    /**
+     * Used for dynamic policy output mixes. Only used by the audio policy.
+     *
+     * Value reserved for system use only. HALs must never return this value to
+     * the system or accept it from the system.
+     */
+    SYS_RESERVED_REROUTING = 12,
+    /**
+     * Used for audio flinger tracks volume. Only used by the audioflinger.
+     *
+     * Value reserved for system use only. HALs must never return this value to
+     * the system or accept it from the system.
+     */
+    SYS_RESERVED_PATCH = 13,
+    /** Used for the stream corresponding to the call assistant usage. */
+    CALL_ASSISTANT = 14,
 }
diff --git a/media/aidl/android/media/audio/common/AudioUsage.aidl b/media/aidl/android/media/audio/common/AudioUsage.aidl
index 028eefe..34a7185 100644
--- a/media/aidl/android/media/audio/common/AudioUsage.aidl
+++ b/media/aidl/android/media/audio/common/AudioUsage.aidl
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
- // This file has been semi-automatically generated using hidl2aidl from its counterpart in
- // hardware/interfaces/audio/common/5.0/types.hal
-
 package android.media.audio.common;
 
 /**
@@ -26,21 +23,119 @@
 @Backing(type="int")
 enum AudioUsage {
     /**
-     * Used as default value in parcelables to indicate that a value was not set.
-     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     * Used as default value in parcelables to indicate that a value was not
+     * set. Should never be considered a valid setting, except for backward
+     * compatibility scenarios.
      */
     INVALID = -1,
+    /**
+     * Usage value to use when the usage is unknown.
+     */
     UNKNOWN = 0,
+    /**
+     * Usage value to use when the usage is media, such as music, or movie
+     * soundtracks.
+     */
     MEDIA = 1,
+    /**
+     * Usage value to use when the usage is voice communications, such as
+     * telephony or VoIP.
+     */
     VOICE_COMMUNICATION = 2,
+    /**
+     * Usage value to use when the usage is in-call signalling, such as with
+     * a "busy" beep, or DTMF tones.
+     */
     VOICE_COMMUNICATION_SIGNALLING = 3,
+    /**
+     * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
+     */
     ALARM = 4,
+    /**
+     * Usage value to use when the usage is notification. See other notification
+     * usages for more specialized uses.
+     */
     NOTIFICATION = 5,
+    /**
+     * Usage value to use when the usage is telephony ringtone.
+     */
     NOTIFICATION_TELEPHONY_RINGTONE = 6,
+    /**
+     * Usage value to use when the usage is a request to enter/end a
+     * communication, such as a VoIP communication or video-conference.
+     *
+     * Value reserved for system use only. HALs must never return this value to
+     * the system or accept it from the system.
+     */
+    SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+    /**
+     * Usage value to use when the usage is notification for an "instant"
+     * communication such as a chat, or SMS.
+     *
+     * Value reserved for system use only. HALs must never return this value to
+     * the system or accept it from the system.
+     */
+    SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+    /**
+     * Usage value to use when the usage is notification for a
+     * non-immediate type of communication such as e-mail.
+     *
+     * Value reserved for system use only. HALs must never return this value to
+     * the system or accept it from the system.
+     */
+    SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+    /**
+     * Usage value to use when the usage is to attract the user's attention,
+     * such as a reminder or low battery warning.
+     */
+    NOTIFICATION_EVENT = 10,
+    /**
+     * Usage value to use when the usage is for accessibility, such as with
+     * a screen reader.
+     */
     ASSISTANCE_ACCESSIBILITY = 11,
+    /**
+     * Usage value to use when the usage is driving or navigation directions.
+     */
     ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+    /**
+     * Usage value to use when the usage is sonification, such as  with user
+     * interface sounds.
+     */
     ASSISTANCE_SONIFICATION = 13,
+    /**
+     * Usage value to use when the usage is for game audio.
+     */
     GAME = 14,
+    /**
+     * Usage value to use when feeding audio to the platform and replacing
+     * "traditional" audio source, such as audio capture devices.
+     */
     VIRTUAL_SOURCE = 15,
+    /**
+     * Usage value to use for audio responses to user queries, audio
+     * instructions or help utterances.
+     */
     ASSISTANT = 16,
+    /**
+     * Usage value to use for assistant voice interaction with remote caller on
+     * Cell and VoIP calls.
+     */
+    CALL_ASSISTANT = 17,
+    /**
+     * Usage value to use when the usage is an emergency.
+     */
+    EMERGENCY = 1000,
+    /**
+     * Usage value to use when the usage is a safety sound.
+     */
+    SAFETY = 1001,
+    /**
+     * Usage value to use when the usage is a vehicle status.
+     */
+    VEHICLE_STATUS = 1002,
+    /**
+     * Usage value to use when the usage is an announcement.
+     */
+    ANNOUNCEMENT = 1003,
 }
diff --git a/media/aidl/android/media/audio/common/PcmType.aidl b/media/aidl/android/media/audio/common/PcmType.aidl
new file mode 100644
index 0000000..db77769
--- /dev/null
+++ b/media/aidl/android/media/audio/common/PcmType.aidl
@@ -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 android.media.audio.common;
+
+/**
+ * The type of the encoding used for representing PCM samples. Only used as
+ * part of 'AudioFormatDescription' structure.
+ */
+@VintfStability
+@Backing(type="byte")
+enum PcmType {
+    /**
+     * "Default" value used when the type 'AudioFormatDescription' is "default".
+     */
+    DEFAULT = 0,
+    /**
+     * Unsigned 8-bit integer.
+     */
+    UINT_8_BIT = DEFAULT,
+    /**
+     * Signed 16-bit integer.
+     */
+    INT_16_BIT = 1,
+    /**
+     * Signed 32-bit integer.
+     */
+    INT_32_BIT = 2,
+    /**
+     * Q8.24 fixed point format.
+     */
+    FIXED_Q_8_24 = 3,
+    /**
+     * IEEE 754 32-bit floating point format.
+     */
+    FLOAT_32_BIT = 4,
+    /**
+     * Signed 24-bit integer.
+     */
+    INT_24_BIT = 5,
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelLayout.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelLayout.aidl
new file mode 100644
index 0000000..6845ac1
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelLayout.aidl
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+union AudioChannelLayout {
+  int none = 0;
+  int invalid = 0;
+  int indexMask;
+  int layoutMask;
+  int voiceMask;
+  const int INDEX_MASK_1 = 1;
+  const int INDEX_MASK_2 = 3;
+  const int INDEX_MASK_3 = 7;
+  const int INDEX_MASK_4 = 15;
+  const int INDEX_MASK_5 = 31;
+  const int INDEX_MASK_6 = 63;
+  const int INDEX_MASK_7 = 127;
+  const int INDEX_MASK_8 = 255;
+  const int INDEX_MASK_9 = 511;
+  const int INDEX_MASK_10 = 1023;
+  const int INDEX_MASK_11 = 2047;
+  const int INDEX_MASK_12 = 4095;
+  const int INDEX_MASK_13 = 8191;
+  const int INDEX_MASK_14 = 16383;
+  const int INDEX_MASK_15 = 32767;
+  const int INDEX_MASK_16 = 65535;
+  const int INDEX_MASK_17 = 131071;
+  const int INDEX_MASK_18 = 262143;
+  const int INDEX_MASK_19 = 524287;
+  const int INDEX_MASK_20 = 1048575;
+  const int INDEX_MASK_21 = 2097151;
+  const int INDEX_MASK_22 = 4194303;
+  const int INDEX_MASK_23 = 8388607;
+  const int INDEX_MASK_24 = 16777215;
+  const int LAYOUT_MONO = 1;
+  const int LAYOUT_STEREO = 3;
+  const int LAYOUT_2POINT1 = 11;
+  const int LAYOUT_TRI = 7;
+  const int LAYOUT_TRI_BACK = 259;
+  const int LAYOUT_3POINT1 = 15;
+  const int LAYOUT_2POINT0POINT2 = 786435;
+  const int LAYOUT_2POINT1POINT2 = 786443;
+  const int LAYOUT_3POINT0POINT2 = 786439;
+  const int LAYOUT_3POINT1POINT2 = 786447;
+  const int LAYOUT_QUAD = 51;
+  const int LAYOUT_QUAD_SIDE = 1539;
+  const int LAYOUT_SURROUND = 263;
+  const int LAYOUT_PENTA = 55;
+  const int LAYOUT_5POINT1 = 63;
+  const int LAYOUT_5POINT1_SIDE = 1551;
+  const int LAYOUT_5POINT1POINT2 = 786495;
+  const int LAYOUT_5POINT1POINT4 = 184383;
+  const int LAYOUT_6POINT1 = 319;
+  const int LAYOUT_7POINT1 = 1599;
+  const int LAYOUT_7POINT1POINT2 = 788031;
+  const int LAYOUT_7POINT1POINT4 = 185919;
+  const int LAYOUT_9POINT1POINT4 = 50517567;
+  const int LAYOUT_9POINT1POINT6 = 51303999;
+  const int LAYOUT_13POINT_360RA = 7534087;
+  const int LAYOUT_22POINT2 = 16777215;
+  const int LAYOUT_MONO_HAPTIC_A = 1073741825;
+  const int LAYOUT_STEREO_HAPTIC_A = 1073741827;
+  const int LAYOUT_HAPTIC_AB = 1610612736;
+  const int LAYOUT_MONO_HAPTIC_AB = 1610612737;
+  const int LAYOUT_STEREO_HAPTIC_AB = 1610612739;
+  const int LAYOUT_FRONT_BACK = 260;
+  const int INTERLEAVE_LEFT = 0;
+  const int INTERLEAVE_RIGHT = 1;
+  const int CHANNEL_FRONT_LEFT = 1;
+  const int CHANNEL_FRONT_RIGHT = 2;
+  const int CHANNEL_FRONT_CENTER = 4;
+  const int CHANNEL_LOW_FREQUENCY = 8;
+  const int CHANNEL_BACK_LEFT = 16;
+  const int CHANNEL_BACK_RIGHT = 32;
+  const int CHANNEL_FRONT_LEFT_OF_CENTER = 64;
+  const int CHANNEL_FRONT_RIGHT_OF_CENTER = 128;
+  const int CHANNEL_BACK_CENTER = 256;
+  const int CHANNEL_SIDE_LEFT = 512;
+  const int CHANNEL_SIDE_RIGHT = 1024;
+  const int CHANNEL_TOP_CENTER = 2048;
+  const int CHANNEL_TOP_FRONT_LEFT = 4096;
+  const int CHANNEL_TOP_FRONT_CENTER = 8192;
+  const int CHANNEL_TOP_FRONT_RIGHT = 16384;
+  const int CHANNEL_TOP_BACK_LEFT = 32768;
+  const int CHANNEL_TOP_BACK_CENTER = 65536;
+  const int CHANNEL_TOP_BACK_RIGHT = 131072;
+  const int CHANNEL_TOP_SIDE_LEFT = 262144;
+  const int CHANNEL_TOP_SIDE_RIGHT = 524288;
+  const int CHANNEL_BOTTOM_FRONT_LEFT = 1048576;
+  const int CHANNEL_BOTTOM_FRONT_CENTER = 2097152;
+  const int CHANNEL_BOTTOM_FRONT_RIGHT = 4194304;
+  const int CHANNEL_LOW_FREQUENCY_2 = 8388608;
+  const int CHANNEL_FRONT_WIDE_LEFT = 16777216;
+  const int CHANNEL_FRONT_WIDE_RIGHT = 33554432;
+  const int CHANNEL_HAPTIC_B = 536870912;
+  const int CHANNEL_HAPTIC_A = 1073741824;
+  const int VOICE_UPLINK_MONO = 16384;
+  const int VOICE_DNLINK_MONO = 32768;
+  const int VOICE_CALL_MONO = 49152;
+  const int CHANNEL_VOICE_UPLINK = 16384;
+  const int CHANNEL_VOICE_DNLINK = 32768;
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelMask.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelMask.aidl
deleted file mode 100644
index c3af3bf..0000000
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelMask.aidl
+++ /dev/null
@@ -1,111 +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.
- */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
-// hardware/interfaces/audio/common/5.0/types.hal
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.media.audio.common;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum AudioChannelMask {
-  REPRESENTATION_POSITION = 0,
-  REPRESENTATION_INDEX = 2,
-  NONE = 0,
-  INVALID = -1073741824,
-  OUT_FRONT_LEFT = 1,
-  OUT_FRONT_RIGHT = 2,
-  OUT_FRONT_CENTER = 4,
-  OUT_LOW_FREQUENCY = 8,
-  OUT_BACK_LEFT = 16,
-  OUT_BACK_RIGHT = 32,
-  OUT_FRONT_LEFT_OF_CENTER = 64,
-  OUT_FRONT_RIGHT_OF_CENTER = 128,
-  OUT_BACK_CENTER = 256,
-  OUT_SIDE_LEFT = 512,
-  OUT_SIDE_RIGHT = 1024,
-  OUT_TOP_CENTER = 2048,
-  OUT_TOP_FRONT_LEFT = 4096,
-  OUT_TOP_FRONT_CENTER = 8192,
-  OUT_TOP_FRONT_RIGHT = 16384,
-  OUT_TOP_BACK_LEFT = 32768,
-  OUT_TOP_BACK_CENTER = 65536,
-  OUT_TOP_BACK_RIGHT = 131072,
-  OUT_TOP_SIDE_LEFT = 262144,
-  OUT_TOP_SIDE_RIGHT = 524288,
-  OUT_HAPTIC_A = 536870912,
-  OUT_HAPTIC_B = 268435456,
-  OUT_MONO = 1,
-  OUT_STEREO = 3,
-  OUT_2POINT1 = 11,
-  OUT_2POINT0POINT2 = 786435,
-  OUT_2POINT1POINT2 = 786443,
-  OUT_3POINT0POINT2 = 786439,
-  OUT_3POINT1POINT2 = 786447,
-  OUT_QUAD = 51,
-  OUT_QUAD_BACK = 51,
-  OUT_QUAD_SIDE = 1539,
-  OUT_SURROUND = 263,
-  OUT_PENTA = 55,
-  OUT_5POINT1 = 63,
-  OUT_5POINT1_BACK = 63,
-  OUT_5POINT1_SIDE = 1551,
-  OUT_5POINT1POINT2 = 786495,
-  OUT_5POINT1POINT4 = 184383,
-  OUT_6POINT1 = 319,
-  OUT_7POINT1 = 1599,
-  OUT_7POINT1POINT2 = 788031,
-  OUT_7POINT1POINT4 = 185919,
-  OUT_MONO_HAPTIC_A = 536870913,
-  OUT_STEREO_HAPTIC_A = 536870915,
-  OUT_HAPTIC_AB = 805306368,
-  OUT_MONO_HAPTIC_AB = 805306369,
-  OUT_STEREO_HAPTIC_AB = 805306371,
-  IN_LEFT = 4,
-  IN_RIGHT = 8,
-  IN_FRONT = 16,
-  IN_BACK = 32,
-  IN_LEFT_PROCESSED = 64,
-  IN_RIGHT_PROCESSED = 128,
-  IN_FRONT_PROCESSED = 256,
-  IN_BACK_PROCESSED = 512,
-  IN_PRESSURE = 1024,
-  IN_X_AXIS = 2048,
-  IN_Y_AXIS = 4096,
-  IN_Z_AXIS = 8192,
-  IN_BACK_LEFT = 65536,
-  IN_BACK_RIGHT = 131072,
-  IN_CENTER = 262144,
-  IN_LOW_FREQUENCY = 1048576,
-  IN_TOP_LEFT = 2097152,
-  IN_TOP_RIGHT = 4194304,
-  IN_VOICE_UPLINK = 16384,
-  IN_VOICE_DNLINK = 32768,
-}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl
index c11eb76..6b8686c 100644
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl
@@ -12,8 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
-// hardware/interfaces/audio/common/5.0/types.hal
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -36,9 +35,7 @@
 /* @hide */
 @JavaDerive(equals=true, toString=true) @VintfStability
 parcelable AudioConfig {
-  int sampleRateHz;
-  int channelMask;
-  android.media.audio.common.AudioFormat format = android.media.audio.common.AudioFormat.INVALID;
+  android.media.audio.common.AudioConfigBase base;
   android.media.audio.common.AudioOffloadInfo offloadInfo;
   long frameCount;
 }
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfigBase.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfigBase.aidl
new file mode 100644
index 0000000..f3e716b
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfigBase.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioConfigBase {
+  int sampleRate;
+  android.media.audio.common.AudioChannelLayout channelMask;
+  android.media.audio.common.AudioFormatDescription format;
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioEncapsulationMode.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioEncapsulationMode.aidl
new file mode 100644
index 0000000..0cf2f31
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioEncapsulationMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum AudioEncapsulationMode {
+  INVALID = -1,
+  NONE = 0,
+  ELEMENTARY_STREAM = 1,
+  HANDLE = 2,
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormat.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormat.aidl
deleted file mode 100644
index b7c8659..0000000
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormat.aidl
+++ /dev/null
@@ -1,109 +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.
- */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
-// hardware/interfaces/audio/common/5.0/types.hal
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.media.audio.common;
-/* @hide */
-@Backing(type="int") @VintfStability
-enum AudioFormat {
-  INVALID = -1,
-  DEFAULT = 0,
-  PCM = 0,
-  MP3 = 16777216,
-  AMR_NB = 33554432,
-  AMR_WB = 50331648,
-  AAC = 67108864,
-  HE_AAC_V1 = 83886080,
-  HE_AAC_V2 = 100663296,
-  VORBIS = 117440512,
-  OPUS = 134217728,
-  AC3 = 150994944,
-  E_AC3 = 167772160,
-  DTS = 184549376,
-  DTS_HD = 201326592,
-  IEC61937 = 218103808,
-  DOLBY_TRUEHD = 234881024,
-  EVRC = 268435456,
-  EVRCB = 285212672,
-  EVRCWB = 301989888,
-  EVRCNW = 318767104,
-  AAC_ADIF = 335544320,
-  WMA = 352321536,
-  WMA_PRO = 369098752,
-  AMR_WB_PLUS = 385875968,
-  MP2 = 402653184,
-  QCELP = 419430400,
-  DSD = 436207616,
-  FLAC = 452984832,
-  ALAC = 469762048,
-  APE = 486539264,
-  AAC_ADTS = 503316480,
-  SBC = 520093696,
-  APTX = 536870912,
-  APTX_HD = 553648128,
-  AC4 = 570425344,
-  LDAC = 587202560,
-  MAT = 603979776,
-  AAC_LATM = 620756992,
-  CELT = 637534208,
-  APTX_ADAPTIVE = 654311424,
-  LHDC = 671088640,
-  LHDC_LL = 687865856,
-  APTX_TWSP = 704643072,
-  MAIN_MASK = -16777216,
-  SUB_MASK = 16777215,
-  PCM_SUB_16_BIT = 1,
-  PCM_SUB_8_BIT = 2,
-  PCM_SUB_32_BIT = 3,
-  PCM_SUB_8_24_BIT = 4,
-  PCM_SUB_FLOAT = 5,
-  PCM_SUB_24_BIT_PACKED = 6,
-  MP3_SUB_NONE = 0,
-  AMR_SUB_NONE = 0,
-  AAC_SUB_MAIN = 1,
-  AAC_SUB_LC = 2,
-  AAC_SUB_SSR = 4,
-  AAC_SUB_LTP = 8,
-  AAC_SUB_HE_V1 = 16,
-  AAC_SUB_SCALABLE = 32,
-  AAC_SUB_ERLC = 64,
-  AAC_SUB_LD = 128,
-  AAC_SUB_HE_V2 = 256,
-  AAC_SUB_ELD = 512,
-  AAC_SUB_XHE = 768,
-  VORBIS_SUB_NONE = 0,
-  E_AC3_SUB_JOC = 1,
-  MAT_SUB_1_0 = 1,
-  MAT_SUB_2_0 = 2,
-  MAT_SUB_2_1 = 3,
-}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormatDescription.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormatDescription.aidl
new file mode 100644
index 0000000..58c75eb
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormatDescription.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioFormatDescription {
+  android.media.audio.common.AudioFormatType type = android.media.audio.common.AudioFormatType.DEFAULT;
+  android.media.audio.common.PcmType pcm = android.media.audio.common.PcmType.DEFAULT;
+  @utf8InCpp String encoding;
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormatType.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormatType.aidl
new file mode 100644
index 0000000..b94c850
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormatType.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+@Backing(type="byte") @VintfStability
+enum AudioFormatType {
+  DEFAULT = 0,
+  NON_PCM = 0,
+  PCM = 1,
+  SYS_RESERVED_INVALID = -1,
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl
index b5d889e..40bd53b2 100644
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl
@@ -12,8 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
-// hardware/interfaces/audio/common/5.0/types.hal
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -36,15 +35,16 @@
 /* @hide */
 @JavaDerive(equals=true, toString=true) @VintfStability
 parcelable AudioOffloadInfo {
-  int sampleRateHz;
-  int channelMask;
-  android.media.audio.common.AudioFormat format = android.media.audio.common.AudioFormat.INVALID;
+  android.media.audio.common.AudioConfigBase base;
   android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
   int bitRatePerSecond;
-  long durationMicroseconds;
+  long durationUs;
   boolean hasVideo;
   boolean isStreaming;
-  int bitWidth;
-  int bufferSize;
+  int bitWidth = 16;
+  int offloadBufferSize;
   android.media.audio.common.AudioUsage usage = android.media.audio.common.AudioUsage.INVALID;
+  android.media.audio.common.AudioEncapsulationMode encapsulationMode = android.media.audio.common.AudioEncapsulationMode.INVALID;
+  int contentId;
+  int syncId;
 }
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl
index 915c668..cbca6c5 100644
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl
@@ -12,8 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
-// hardware/interfaces/audio/common/5.0/types.hal
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -38,7 +37,6 @@
 enum AudioStreamType {
   INVALID = -2,
   DEFAULT = -1,
-  MIN = 0,
   VOICE_CALL = 0,
   SYSTEM = 1,
   RING = 2,
@@ -50,4 +48,8 @@
   DTMF = 8,
   TTS = 9,
   ACCESSIBILITY = 10,
+  ASSISTANT = 11,
+  SYS_RESERVED_REROUTING = 12,
+  SYS_RESERVED_PATCH = 13,
+  CALL_ASSISTANT = 14,
 }
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl
index f5130a4..4c72455 100644
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl
@@ -12,8 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
-// hardware/interfaces/audio/common/5.0/types.hal
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
@@ -44,10 +43,19 @@
   ALARM = 4,
   NOTIFICATION = 5,
   NOTIFICATION_TELEPHONY_RINGTONE = 6,
+  SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+  SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+  SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+  NOTIFICATION_EVENT = 10,
   ASSISTANCE_ACCESSIBILITY = 11,
   ASSISTANCE_NAVIGATION_GUIDANCE = 12,
   ASSISTANCE_SONIFICATION = 13,
   GAME = 14,
   VIRTUAL_SOURCE = 15,
   ASSISTANT = 16,
+  CALL_ASSISTANT = 17,
+  EMERGENCY = 1000,
+  SAFETY = 1001,
+  VEHICLE_STATUS = 1002,
+  ANNOUNCEMENT = 1003,
 }
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/PcmType.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/PcmType.aidl
new file mode 100644
index 0000000..42c4679
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/PcmType.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+@Backing(type="byte") @VintfStability
+enum PcmType {
+  DEFAULT = 0,
+  UINT_8_BIT = 0,
+  INT_16_BIT = 1,
+  INT_32_BIT = 2,
+  FIXED_Q_8_24 = 3,
+  FLOAT_32_BIT = 4,
+  INT_24_BIT = 5,
+}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 07444ea..54252b5 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -141,17 +141,26 @@
     /**
      * Usage value to use when the usage is a request to enter/end a
      * communication, such as a VoIP communication or video-conference.
+     * @deprecated Use {@link #USAGE_NOTIFICATION} which is handled
+     *             the same way as this usage by the audio framework
      */
+    @Deprecated
     public final static int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7;
     /**
      * Usage value to use when the usage is notification for an "instant"
      * communication such as a chat, or SMS.
+     * @deprecated Use {@link #USAGE_NOTIFICATION} which is handled
+     *             the same way as this usage by the audio framework
      */
+    @Deprecated
     public final static int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8;
     /**
      * Usage value to use when the usage is notification for a
      * non-immediate type of communication such as e-mail.
+     * @deprecated Use {@link #USAGE_NOTIFICATION} which is handled
+     *             the same way as this usage by the audio framework
      */
+    @Deprecated
     public final static int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9;
     /**
      * Usage value to use when the usage is to attract the user's attention,
@@ -459,13 +468,26 @@
      */
     public static final int FLAG_CAPTURE_PRIVATE = 0x1 << 13;
 
+    /**
+     * @hide
+     * Flag indicating the audio content has been processed to provide a virtual multichannel
+     * audio experience
+     */
+    public static final int FLAG_CONTENT_SPATIALIZED = 0x1 << 14;
+
+    /**
+     * @hide
+     * Flag indicating the audio content is to never be spatialized
+     */
+    public static final int FLAG_NEVER_SPATIALIZE = 0x1 << 15;
 
     // Note that even though FLAG_MUTE_HAPTIC is stored as a flag bit, it is not here since
     // it is known as a boolean value outside of AudioAttributes.
     private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
             | FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
             | FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
-            | FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE;
+            | FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE | FLAG_CONTENT_SPATIALIZED
+            | FLAG_NEVER_SPATIALIZE;
     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
             FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
     /* mask of flags that can be set by SDK and System APIs through the Builder */
@@ -627,6 +649,49 @@
     }
 
     /**
+     * Return true if the audio content associated with these attributes has already been
+     * spatialized, that is it has already been processed to offer a binaural or transaural
+     * immersive audio experience.
+     * @return {@code true} if the content has been processed
+     */
+    public boolean isContentSpatialized() {
+        return (mFlags & FLAG_CONTENT_SPATIALIZED) != 0;
+    }
+
+    /** @hide */
+    @IntDef(flag = false, value = {
+            SPATIALIZATION_BEHAVIOR_AUTO,
+            SPATIALIZATION_BEHAVIOR_NEVER,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SpatializationBehavior {};
+
+    /**
+     * Constant indicating the audio content associated with these attributes will follow the
+     * default platform behavior with regards to which content will be spatialized or not.
+     * @see #getSpatializationBehavior()
+     * @see Spatializer
+     */
+    public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0;
+
+    /**
+     * Constant indicating the audio content associated with these attributes should never
+     * be virtualized.
+     * @see #getSpatializationBehavior()
+     * @see Spatializer
+     */
+    public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1;
+
+    /**
+     * Return the behavior affecting whether spatialization will be used.
+     * @return the spatialization behavior
+     */
+    public @SpatializationBehavior int getSpatializationBehavior() {
+        return ((mFlags & FLAG_NEVER_SPATIALIZE) != 0)
+                ? SPATIALIZATION_BEHAVIOR_NEVER : SPATIALIZATION_BEHAVIOR_AUTO;
+    }
+
+    /**
      * Return the capture policy.
      * @return the capture policy set by {@link Builder#setAllowedCapturePolicy(int)} or
      *         the default if it was not called.
@@ -669,6 +734,8 @@
         private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
         private int mFlags = 0x0;
         private boolean mMuteHapticChannels = true;
+        private boolean mIsContentSpatialized = false;
+        private int mSpatializationBehavior = SPATIALIZATION_BEHAVIOR_AUTO;
         private HashSet<String> mTags = new HashSet<String>();
         private Bundle mBundle;
         private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
@@ -699,6 +766,8 @@
             mFlags = aa.getAllFlags();
             mTags = (HashSet<String>) aa.mTags.clone();
             mMuteHapticChannels = aa.areHapticChannelsMuted();
+            mIsContentSpatialized = aa.isContentSpatialized();
+            mSpatializationBehavior = aa.getSpatializationBehavior();
         }
 
         /**
@@ -726,11 +795,28 @@
                 }
             }
 
+            // handle deprecation of notification usages by remapping to USAGE_NOTIFICATION
+            switch (aa.mUsage) {
+                case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+                case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+                case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+                    aa.mUsage = USAGE_NOTIFICATION;
+                    break;
+                default:
+                    break;
+            }
+
             aa.mSource = mSource;
             aa.mFlags = mFlags;
             if (mMuteHapticChannels) {
                 aa.mFlags |= FLAG_MUTE_HAPTIC;
             }
+            if (mIsContentSpatialized) {
+                aa.mFlags |= FLAG_CONTENT_SPATIALIZED;
+            }
+            if (mSpatializationBehavior == SPATIALIZATION_BEHAVIOR_NEVER) {
+                aa.mFlags |= FLAG_NEVER_SPATIALIZE;
+            }
 
             if (mPrivacySensitive == PRIVACY_SENSITIVE_DEFAULT) {
                 // capturing for camcorder or communication is private by default to
@@ -757,7 +843,6 @@
                     && (mFlags & FLAG_HW_HOTWORD) == FLAG_HW_HOTWORD) {
                 aa.mFlags &= ~FLAG_HW_HOTWORD;
             }
-
             return aa;
         }
 
@@ -770,9 +855,6 @@
          *     {@link AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING},
          *     {@link AttributeSdkUsage#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
          *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_RINGTONE},
-         *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_COMMUNICATION_REQUEST},
-         *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_COMMUNICATION_INSTANT},
-         *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_COMMUNICATION_DELAYED},
          *     {@link AttributeSdkUsage#USAGE_NOTIFICATION_EVENT},
          *     {@link AttributeSdkUsage#USAGE_ASSISTANT},
          *     {@link AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY},
@@ -918,6 +1000,35 @@
         }
 
         /**
+         * Specifies whether the content has already been processed for spatialization.
+         * If it has, setting this to true will prevent issues such as double-processing.
+         * @param isSpatialized
+         * @return the same Builder instance
+         */
+        public @NonNull Builder setIsContentSpatialized(boolean isSpatialized) {
+            mIsContentSpatialized = isSpatialized;
+            return this;
+        }
+
+        /**
+         * Sets the behavior affecting whether spatialization will be used.
+         * @param sb the spatialization behavior
+         * @return the same Builder instance
+         *
+         */
+        public @NonNull Builder setSpatializationBehavior(@SpatializationBehavior int sb) {
+            switch (sb) {
+                case SPATIALIZATION_BEHAVIOR_NEVER:
+                case SPATIALIZATION_BEHAVIOR_AUTO:
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid spatialization behavior " + sb);
+            }
+            mSpatializationBehavior = sb;
+            return this;
+        }
+
+        /**
          * @hide
          * Replaces flags.
          * @param flags any combination of {@link AudioAttributes#FLAG_ALL}.
@@ -1002,6 +1113,8 @@
                     mContentType = attributes.mContentType;
                     mFlags = attributes.getAllFlags();
                     mMuteHapticChannels = attributes.areHapticChannelsMuted();
+                    mIsContentSpatialized = attributes.isContentSpatialized();
+                    mSpatializationBehavior = attributes.getSpatializationBehavior();
                     mTags = attributes.mTags;
                     mBundle = attributes.mBundle;
                     mSource = attributes.mSource;
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index a8199c4..5cdb898 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -495,6 +495,12 @@
     public static final int CHANNEL_OUT_FRONT_WIDE_LEFT = 0x4000000;
     /** Front wide right output channel (see FWR in channel diagram) */
     public static final int CHANNEL_OUT_FRONT_WIDE_RIGHT = 0x8000000;
+    /** @hide
+     * Haptic channels can be used by internal framework code. Use the same values as in native.
+     */
+    public static final int CHANNEL_OUT_HAPTIC_B = 0x10000000;
+    /** @hide */
+    public static final int CHANNEL_OUT_HAPTIC_A = 0x20000000;
 
     public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT;
     public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1a56915..91834fb 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -817,7 +817,7 @@
     }
 
     @UnsupportedAppUsage
-    private static IAudioService getService()
+    static IAudioService getService()
     {
         if (sService != null) {
             return sService;
@@ -2453,6 +2453,25 @@
     }
 
     //====================================================================
+    // Immersive audio
+
+    /**
+     * Return a handle to the optional platform's {@link Spatializer}
+     * @return {@code null} if spatialization is not supported, the {@code Spatializer} instance
+     *         otherwise.
+     */
+    public @Nullable Spatializer getSpatializer() {
+        int level = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+        try {
+            level = getService().getSpatializerImmersiveAudioLevel();
+        } catch (Exception e) { /* using NONE */ }
+        if (level == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) {
+            return null;
+        }
+        return new Spatializer(this);
+    }
+
+    //====================================================================
     // Bluetooth SCO control
     /**
      * Sticky broadcast intent action indicating that the Bluetooth SCO audio
@@ -5808,6 +5827,40 @@
         }
     }
 
+    /**
+    * Indicate Le Audio output device connection state change and eventually suppress
+    * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
+    * @param device Bluetooth device connected/disconnected
+    * @param state new connection state (BluetoothProfile.STATE_xxx)
+    * @param suppressNoisyIntent if true the
+    * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+    * {@hide}
+    */
+    public void setBluetoothLeAudioOutDeviceConnectionState(BluetoothDevice device, int state,
+            boolean suppressNoisyIntent) {
+        final IAudioService service = getService();
+        try {
+            service.setBluetoothLeAudioOutDeviceConnectionState(device, state, suppressNoisyIntent);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+    * Indicate Le Audio input connection state change.
+    * @param device Bluetooth device connected/disconnected
+    * @param state new connection state (BluetoothProfile.STATE_xxx)
+    * {@hide}
+    */
+    public void setBluetoothLeAudioInDeviceConnectionState(BluetoothDevice device, int state) {
+        final IAudioService service = getService();
+        try {
+            service.setBluetoothLeAudioInDeviceConnectionState(device, state);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
      /**
      * Indicate A2DP source or sink connection state change and eventually suppress
      * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
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..60c9e1c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
 import android.bluetooth.BluetoothCodecConfig;
@@ -1769,6 +1770,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.
      */
@@ -1993,6 +2001,46 @@
      */
     public static native int setVibratorInfos(@NonNull List<Vibrator> vibrators);
 
+    /**
+     * @hide
+     * If a spatializer effect is present on the platform, this will return an
+     * ISpatializer interface to control this feature.
+     * If no spatializer is present, a null interface is returned.
+     * The INativeSpatializerCallback passed must not be null.
+     * Only one ISpatializer interface can exist at a given time. The native audio policy
+     * service will reject the request if an interface was already acquired and previous owner
+     * did not die or call ISpatializer.release().
+     * @param callback the callback to receive state updates if the ISpatializer
+     *        interface is acquired.
+     * @return the ISpatializer interface made available to control the
+     *        platform spatializer
+     */
+    @Nullable
+    public static ISpatializer getSpatializer(INativeSpatializerCallback callback) {
+        return ISpatializer.Stub.asInterface(nativeGetSpatializer(callback));
+    }
+    private static native IBinder nativeGetSpatializer(INativeSpatializerCallback callback);
+
+    /**
+     * @hide
+     * Queries if some kind of spatialization will be performed if the audio playback context
+     * described by the provided arguments is present.
+     * The context is made of:
+     * - The audio attributes describing the playback use case.
+     * - The audio configuration describing the audio format, channels, sampling rate ...
+     * - The devices describing the sink audio device selected for playback.
+     * All arguments are optional and only the specified arguments are used to match against
+     * supported criteria. For instance, supplying no argument will tell if spatialization is
+     * supported or not in general.
+     * @param attributes audio attributes describing the playback use case
+     * @param format audio configuration describing the audio format, channels, sampling rate...
+     * @param devices the sink audio device selected for playback
+     * @return true if spatialization is enabled for this context, false otherwise.
+     */
+    public static native boolean canBeSpatialized(AudioAttributes attributes,
+                                              AudioFormat format,
+                                              AudioDeviceAttributes[] devices);
+
     // Items shared with audio service
 
     /**
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 115fb74..5891a18 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -577,7 +577,7 @@
     // 3.1. PNG file signature
     private static final byte[] PNG_SIGNATURE = new byte[] {(byte) 0x89, (byte) 0x50, (byte) 0x4e,
             (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a};
-    // See PNG (Portable Network Graphics) Specification, Version 1.2,
+    // See "Extensions to the PNG 1.2 Specification, Version 1.5.0",
     // 3.7. eXIf Exchangeable Image File (Exif) Profile
     private static final byte[] PNG_CHUNK_TYPE_EXIF = new byte[]{(byte) 0x65, (byte) 0x58,
             (byte) 0x49, (byte) 0x66};
@@ -2085,7 +2085,9 @@
      * <p>
      * For WebP format, the Exif data will be stored as an Extended File Format, and it may not be
      * supported for older readers.
-     * </p>
+     * <p>
+     * For PNG format, the Exif data will be stored as an "eXIf" chunk as per
+     * "Extensions to the PNG 1.2 Specification, Version 1.5.0".
      */
     public void saveAttributes() throws IOException {
         if (!isSupportedFormatForSavingAttributes()) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index b0c4a3b..f6eb0d5 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
+import android.media.AudioFormat;
 import android.media.AudioFocusInfo;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRecordingConfiguration;
@@ -34,6 +35,7 @@
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
 import android.media.IStrategyPreferredDevicesDispatcher;
+import android.media.ISpatializerCallback;
 import android.media.IVolumeController;
 import android.media.IVolumeController;
 import android.media.PlayerBase;
@@ -277,6 +279,11 @@
     void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
             int state, boolean suppressNoisyIntent, int musicDevice);
 
+    void setBluetoothLeAudioOutDeviceConnectionState(in BluetoothDevice device, int state,
+            boolean suppressNoisyIntent);
+
+    void setBluetoothLeAudioInDeviceConnectionState(in BluetoothDevice device, int state);
+
     void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
             int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
 
@@ -396,4 +403,24 @@
     void registerModeDispatcher(IAudioModeDispatcher dispatcher);
 
     oneway void unregisterModeDispatcher(IAudioModeDispatcher dispatcher);
+
+    int getSpatializerImmersiveAudioLevel();
+
+    boolean isSpatializerEnabled();
+
+    boolean isSpatializerAvailable();
+
+    void setSpatializerEnabled(boolean enabled);
+
+    boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
+
+    void registerSpatializerCallback(in ISpatializerCallback callback);
+
+    void unregisterSpatializerCallback(in ISpatializerCallback callback);
+
+    List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices();
+
+    void addSpatializerCompatibleAudioDevice(in AudioDeviceAttributes ada);
+
+    void removeSpatializerCompatibleAudioDevice(in AudioDeviceAttributes ada);
 }
diff --git a/core/java/android/uwb/MeasurementStatus.aidl b/media/java/android/media/ISpatializerCallback.aidl
similarity index 63%
rename from core/java/android/uwb/MeasurementStatus.aidl
rename to media/java/android/media/ISpatializerCallback.aidl
index 5fa1554..50f91e7 100644
--- a/core/java/android/uwb/MeasurementStatus.aidl
+++ b/media/java/android/media/ISpatializerCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,26 +14,16 @@
  * limitations under the License.
  */
 
-package android.uwb;
+package android.media;
 
 /**
- * @hide
+ * AIDL for the AudioService to signal Spatializer state changes.
+ *
+ * {@hide}
  */
-@Backing(type="int")
-enum MeasurementStatus {
-  /**
-   * Ranging was successful
-   */
-  SUCCESS,
+oneway interface ISpatializerCallback {
 
-  /**
-   * The remote device is out of range
-   */
-  FAILURE_OUT_OF_RANGE,
+    void dispatchSpatializerEnabledChanged(boolean enabled);
 
-  /**
-   * An unknown failure has occurred.
-   */
-   FAILURE_UNKNOWN,
+    void dispatchSpatializerAvailableChanged(boolean available);
 }
-
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 9bf0db5..16543b0 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -174,6 +174,67 @@
     public static final String MIMETYPE_AUDIO_MPEGH_MHA1 = "audio/mha1";
     /** MIME type for MPEG-H Audio single stream, encapsulated in MHAS */
     public static final String MIMETYPE_AUDIO_MPEGH_MHM1 = "audio/mhm1";
+    /** MIME type for DTS (up to 5.1 channels) audio stream. */
+    public static final String MIMETYPE_AUDIO_DTS = "audio/vnd.dts";
+    /** MIME type for DTS HD (up to 7.1 channels) audio stream. */
+    public static final String MIMETYPE_AUDIO_DTS_HD = "audio/vnd.dts.hd";
+    /** MIME type for DTS UHD (object-based) audio stream. */
+    public static final String MIMETYPE_AUDIO_DTS_UHD = "audio/vnd.dts.uhd";
+    /** MIME type for Dynamic Resolution Adaptation (DRA) audio stream. */
+    public static final String MIMETYPE_AUDIO_DRA = "audio/vnd.dra";
+    /** MIME type for Dolby Metadata-enhanced Audio Transmission (MAT) audio stream. */
+    public static final String MIMETYPE_AUDIO_DOLBY_MAT = "audio/vnd.dolby.mat";
+    /** MIME type for Dolby TrueHD audio format, based on Meridian Lossless Packing (MLP). */
+    public static final String MIMETYPE_AUDIO_DOLBY_TRUEHD = "audio/vnd.dolby.mlp";
+    /**
+     * MIME type for AAC Low Complexity (LC) audio stream. Uses the scheme defined by
+     * RFC 6381 with OTI of MPEG-4 (40) and AOT of AAC LC (2) from ISO/IEC 14496-3.
+     */
+    public static final String MIMETYPE_AUDIO_AAC_LC = "audio/mp4a.40.02";
+    /**
+     * MIME type for HE-AAC v1 (LC + SBR) audio stream. Uses the scheme defined by
+     * RFC 6381 with OTI of MPEG-4 (40) and AOT of AAC SBR (5) from ISO/IEC 14496-3.
+     */
+    public static final String MIMETYPE_AUDIO_AAC_HE_V1 = "audio/mp4a.40.05";
+    /**
+     * MIME type for HE-AAC v2 (LC + SBR + PS) audio stream. Uses the scheme defined by
+     * RFC 6381 with OTI of MPEG-4 (40) and AOT of PS (29) from ISO/IEC 14496-3.
+     */
+    public static final String MIMETYPE_AUDIO_AAC_HE_V2 = "audio/mp4a.40.29";
+    /**
+     * MIME type for AAC Enhanced Low Delay (ELD) audio stream. Uses the scheme defined by
+     * RFC 6381 with OTI of MPEG-4 (40) and AOT of ELD (39) from ISO/IEC 14496-3.
+     */
+    public static final String MIMETYPE_AUDIO_AAC_ELD = "audio/mp4a.40.39";
+    /**
+     * MIME type for AAC XHE audio stream. Uses the scheme defined by
+     * RFC 6381 with OTI of MPEG-4 (40) and AOT of USAC (42) from ISO/IEC 14496-3.
+     */
+    public static final String MIMETYPE_AUDIO_AAC_XHE = "audio/mp4a.40.42";
+    /**
+     * MIME type for MPEG-H Baseline (BL) Profile L3 audio stream. Uses the scheme defined by
+     * RFC 6381 with mpegh3daProfileLevelIndication for main profile/L3 (0x3) from ISO/IEC 23008-3.
+     */
+    public static final String MIMETYPE_AUDIO_MPEGH_BL_L3 = "audio/mhm1.03";
+    /**
+     * MIME type for MPEG-H Baseline (BL) Profile L4 audio stream. Uses the scheme defined by
+     * RFC 6381 with mpegh3daProfileLevelIndication for main profile/L4 (0x4) from ISO/IEC 23008-3.
+     */
+    public static final String MIMETYPE_AUDIO_MPEGH_BL_L4 = "audio/mhm1.04";
+    /**
+     * MIME type for MPEG-H Low Complexity (LC) L3 audio stream. Uses the scheme defined by
+     * RFC 6381 with mpegh3daProfileLevelIndication for LC profile/L3 (0xD) from ISO/IEC 23008-3.
+     */
+    public static final String MIMETYPE_AUDIO_MPEGH_LC_L3 = "audio/mhm1.0d";
+    /**
+     * MIME type for MPEG-H Low Complexity (LC) L4 audio stream. Uses the scheme defined by
+     * RFC 6381 with mpegh3daProfileLevelIndication for LC profile/L4 (0xE) from ISO/IEC 23008-3.
+     */
+    public static final String MIMETYPE_AUDIO_MPEGH_LC_L4 = "audio/mhm1.0e";
+    /**
+     * MIME type for the IEC61937 audio stream encapsulation. This type isn't defined by IANA.
+     */
+    public static final String MIMETYPE_AUDIO_IEC61937 = "audio/x-iec61937";
 
     /**
      * MIME type for HEIF still image data encoded in HEVC.
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index ac19c21..b8e7930e 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -69,17 +69,14 @@
 
  <h4>Metadata Track</h4>
  <p>
-  Per-frame metadata is useful in carrying extra information that correlated with video or audio to
-  facilitate offline processing, e.g. gyro signals from the sensor could help video stabilization when
-  doing offline processing. Metadata track is only supported in MP4 container. When adding a new
-  metadata track, track's mime format must start with prefix "application/", e.g. "applicaton/gyro".
-  Metadata's format/layout will be defined by the application. Writing metadata is nearly the same as
-  writing video/audio data except that the data will not be from mediacodec. Application just needs
-  to pass the bytebuffer that contains the metadata and also the associated timestamp to the
-  {@link #writeSampleData} api. The timestamp must be in the same time base as video and audio. The
-  generated MP4 file uses TextMetaDataSampleEntry defined in section 12.3.3.2 of the ISOBMFF to signal
-  the metadata's mime format. When using{@link android.media.MediaExtractor} to extract the file with
-  metadata track, the mime format of the metadata will be extracted into {@link android.media.MediaFormat}.
+  Per-frame metadata carries information that correlates with video or audio to facilitate offline
+  processing. For example, gyro signals from the sensor can help video stabilization when doing
+  offline processing. Metadata tracks are only supported when multiplexing to the MP4 container
+  format. When adding a new metadata track, the MIME type format must start with prefix
+  "application/" (for example, "application/gyro"). The format of the metadata is
+  application-defined. Metadata timestamps must be in the same time base as video and audio
+  timestamps. The generated MP4 file uses TextMetaDataSampleEntry (defined in section 12.3.3.2 of
+  the ISOBMFF specification) to signal the metadata's MIME type.
 
  <pre class=prettyprint>
    MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4);
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index cf06fad..813dee3 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -1,9 +1,9 @@
 # Bug component: 1344
-
 fgoldfain@google.com
 elaurent@google.com
 lajos@google.com
-olly@google.com
-andrewlewis@google.com
 sungsoo@google.com
 jmtrivi@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 86ed50b..72ee00f 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -102,6 +102,13 @@
         mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
     };
 
+    /** @hide */
+    public int getPlayerIId() {
+        synchronized (mLock) {
+            return mPlayerIId;
+        }
+    }
+
     /**
      * Call from derived class when instantiation / initialization is successful
      */
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
new file mode 100644
index 0000000..3ed8b58
--- /dev/null
+++ b/media/java/android/media/Spatializer.java
@@ -0,0 +1,404 @@
+/*
+ * 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.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.media.permission.ClearCallingIdentityContext;
+import android.media.permission.SafeCloseable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Spatializer provides access to querying capabilities and behavior of sound spatialization
+ * on the device.
+ * Sound spatialization simulates sounds originating around the listener as if they were coming
+ * from virtual speakers placed around the listener.<br>
+ * Support for spatialization is optional, use {@link AudioManager#getSpatializer()} to obtain an
+ * instance of this class if the feature is supported.
+ *
+ */
+public class Spatializer {
+
+    private final @NonNull AudioManager mAm;
+
+    private final Object mStateListenerLock = new Object();
+
+    private static final String TAG = "Spatializer";
+
+    /**
+     * List of listeners for state listener and their associated Executor.
+     * List is lazy-initialized on first registration
+     */
+    @GuardedBy("mStateListenerLock")
+    private @Nullable ArrayList<StateListenerInfo> mStateListeners;
+
+    @GuardedBy("mStateListenerLock")
+    private SpatializerInfoDispatcherStub mInfoDispatcherStub;
+
+    /**
+     * @hide
+     * Constructor with AudioManager acting as proxy to AudioService
+     * @param am a non-null AudioManager
+     */
+    protected Spatializer(@NonNull AudioManager am) {
+        mAm = Objects.requireNonNull(am);
+    }
+
+    /**
+     * Returns whether spatialization is enabled or not.
+     * A false value can originate for instance from the user electing to
+     * disable the feature.<br>
+     * Note that this state reflects a platform-wide state of the "desire" to use spatialization,
+     * but availability of the audio processing is still dictated by the compatibility between
+     * the effect and the hardware configuration, as indicated by {@link #isAvailable()}.
+     * @return {@code true} if spatialization is enabled
+     * @see #isAvailable()
+     */
+    public boolean isEnabled() {
+        try {
+            return mAm.getService().isSpatializerEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error querying isSpatializerEnabled, returning false", e);
+            return false;
+        }
+    }
+
+    /**
+     * Returns whether spatialization is available.
+     * Reasons for spatialization being unavailable include situations where audio output is
+     * incompatible with sound spatialization, such as playback on a monophonic speaker.<br>
+     * Note that spatialization can be available, but disabled by the user, in which case this
+     * method would still return {@code true}, whereas {@link #isEnabled()}
+     * would return {@code false}.
+     * @return {@code true} if the spatializer effect is available and capable
+     *         of processing the audio for the current configuration of the device,
+     *         {@code false} otherwise.
+     * @see #isEnabled()
+     */
+    public boolean isAvailable()  {
+        try {
+            return mAm.getService().isSpatializerAvailable();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error querying isSpatializerAvailable, returning false", e);
+            return false;
+        }
+    }
+
+    /** @hide */
+    @IntDef(flag = false, value = {
+            SPATIALIZER_IMMERSIVE_LEVEL_NONE,
+            SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImmersiveAudioLevel {};
+
+    /**
+     * @hide
+     * Constant indicating there are no spatialization capabilities supported on this device.
+     * @see AudioManager#getImmersiveAudioLevel()
+     */
+    public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0;
+
+    /**
+     * @hide
+     * Constant indicating the {@link Spatializer} on this device supports multichannel
+     * spatialization.
+     * @see AudioManager#getImmersiveAudioLevel()
+     */
+    public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1;
+
+    /**
+     * @hide
+     * Enables / disables the spatializer effect.
+     * Changing the enabled state will trigger the public
+     * {@link OnSpatializerStateChangedListener#onSpatializerEnabledChanged(Spatializer, boolean)}
+     * registered listeners.
+     * @param enabled {@code true} for enabling the effect
+     */
+    @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+    public void setEnabled(boolean enabled) {
+        try {
+            mAm.getService().setSpatializerEnabled(enabled);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling setSpatializerEnabled", e);
+        }
+    }
+
+    /**
+     * An interface to be notified of changes to the state of the spatializer.
+     */
+    public interface OnSpatializerStateChangedListener {
+        /**
+         * Called when the enabled state of the spatializer effect changes
+         * @param spat the {@code Spatializer} instance whose state changed
+         * @param enabled {@code true} if the spatializer effect is enabled on the device,
+         *                            {@code false} otherwise
+         * @see #isEnabled()
+         */
+        void onSpatializerEnabledChanged(@NonNull Spatializer spat, boolean enabled);
+
+        /**
+         * Called when the availability of the spatializer effect changes
+         * @param spat the {@code Spatializer} instance whose state changed
+         * @param available {@code true} if the spatializer effect is available and capable
+         *                  of processing the audio for the current configuration of the device,
+         *                  {@code false} otherwise.
+         * @see #isAvailable()
+         */
+        void onSpatializerAvailableChanged(@NonNull Spatializer spat, boolean available);
+    }
+
+    /**
+     * Returns whether audio of the given {@link AudioFormat}, played with the given
+     * {@link AudioAttributes} can be spatialized.
+     * Note that the result reflects the capabilities of the device and may change when
+     * audio accessories are connected/disconnected (e.g. wired headphones plugged in or not).
+     * The result is independent from whether spatialization processing is enabled or not.
+     * @param attributes the {@code AudioAttributes} of the content as used for playback
+     * @param format the {@code AudioFormat} of the content as used for playback
+     * @return {@code true} if the device is capable of spatializing the combination of audio format
+     *     and attributes, {@code false} otherwise.
+     */
+    public boolean canBeSpatialized(
+            @NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
+        try {
+            return mAm.getService().canBeSpatialized(
+                    Objects.requireNonNull(attributes), Objects.requireNonNull(format));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error querying canBeSpatialized for attr:" + attributes
+                    + " format:" + format + " returning false", e);
+            return false;
+        }
+    }
+
+    /**
+     * Adds a listener to be notified of changes to the enabled state of the
+     * {@code Spatializer}.
+     * @param executor the {@code Executor} handling the callback
+     * @param listener the listener to receive enabled state updates
+     * @see #isEnabled()
+     */
+    public void addOnSpatializerStateChangedListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnSpatializerStateChangedListener listener) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(listener);
+        synchronized (mStateListenerLock) {
+            if (hasSpatializerStateListener(listener)) {
+                throw new IllegalArgumentException(
+                        "Called addOnSpatializerStateChangedListener() "
+                        + "on a previously registered listener");
+            }
+            // lazy initialization of the list of strategy-preferred device listener
+            if (mStateListeners == null) {
+                mStateListeners = new ArrayList<>();
+            }
+            mStateListeners.add(new StateListenerInfo(listener, executor));
+            if (mStateListeners.size() == 1) {
+                // register binder for callbacks
+                if (mInfoDispatcherStub == null) {
+                    mInfoDispatcherStub =
+                            new SpatializerInfoDispatcherStub();
+                }
+                try {
+                    mAm.getService().registerSpatializerCallback(
+                            mInfoDispatcherStub);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes a previously added listener for changes to the enabled state of the
+     * {@code Spatializer}.
+     * @param listener the listener to receive enabled state updates
+     * @see #isEnabled()
+     */
+    public void removeOnSpatializerStateChangedListener(
+            @NonNull OnSpatializerStateChangedListener listener) {
+        Objects.requireNonNull(listener);
+        synchronized (mStateListenerLock) {
+            if (!removeStateListener(listener)) {
+                throw new IllegalArgumentException(
+                        "Called removeOnSpatializerStateChangedListener() "
+                        + "on an unregistered listener");
+            }
+            if (mStateListeners.size() == 0) {
+                // unregister binder for callbacks
+                try {
+                    mAm.getService().unregisterSpatializerCallback(mInfoDispatcherStub);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                } finally {
+                    mInfoDispatcherStub = null;
+                    mStateListeners = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Returns the list of playback devices that are compatible with the playback of multichannel
+     * audio through virtualization
+     * @return a list of devices. An empty list indicates virtualization is not supported.
+     */
+    @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+    public @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
+        try {
+            return mAm.getService().getSpatializerCompatibleAudioDevices();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error querying getSpatializerCompatibleAudioDevices(), "
+                    + " returning empty list", e);
+            return new ArrayList<AudioDeviceAttributes>(0);
+        }
+    }
+
+    /**
+     * @hide
+     * Adds a playback device to the list of devices compatible with the playback of multichannel
+     * audio through spatialization.
+     * @see #getCompatibleAudioDevices()
+     * @param ada the audio device compatible with spatialization
+     */
+    @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+    public void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+        try {
+            mAm.getService().addSpatializerCompatibleAudioDevice(Objects.requireNonNull(ada));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling addSpatializerCompatibleAudioDevice(), ", e);
+        }
+    }
+
+    /**
+     * @hide
+     * Remove a playback device from the list of devices compatible with the playback of
+     * multichannel audio through spatialization.
+     * @see #getCompatibleAudioDevices()
+     * @param ada the audio device incompatible with spatialization
+     */
+    @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+    public void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+        try {
+            mAm.getService().removeSpatializerCompatibleAudioDevice(Objects.requireNonNull(ada));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling removeSpatializerCompatibleAudioDevice(), ", e);
+        }
+    }
+
+    private final class SpatializerInfoDispatcherStub extends ISpatializerCallback.Stub {
+        @Override
+        public void dispatchSpatializerEnabledChanged(boolean enabled) {
+            // make a shallow copy of listeners so callback is not executed under lock
+            final ArrayList<StateListenerInfo> stateListeners;
+            synchronized (mStateListenerLock) {
+                if (mStateListeners == null || mStateListeners.size() == 0) {
+                    return;
+                }
+                stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
+            }
+            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+                for (StateListenerInfo info : stateListeners) {
+                    info.mExecutor.execute(() ->
+                            info.mListener.onSpatializerEnabledChanged(Spatializer.this, enabled));
+                }
+            }
+        }
+
+        @Override
+        public void dispatchSpatializerAvailableChanged(boolean available) {
+            // make a shallow copy of listeners so callback is not executed under lock
+            final ArrayList<StateListenerInfo> stateListeners;
+            synchronized (mStateListenerLock) {
+                if (mStateListeners == null || mStateListeners.size() == 0) {
+                    return;
+                }
+                stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
+            }
+            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+                for (StateListenerInfo info : stateListeners) {
+                    info.mExecutor.execute(() ->
+                            info.mListener.onSpatializerAvailableChanged(
+                                    Spatializer.this, available));
+                }
+            }
+        }
+    }
+
+    private static class StateListenerInfo {
+        final @NonNull OnSpatializerStateChangedListener mListener;
+        final @NonNull Executor mExecutor;
+
+        StateListenerInfo(@NonNull OnSpatializerStateChangedListener listener,
+                @NonNull Executor exe) {
+            mListener = listener;
+            mExecutor = exe;
+        }
+    }
+
+    @GuardedBy("mStateListenerLock")
+    private boolean hasSpatializerStateListener(OnSpatializerStateChangedListener listener) {
+        return getStateListenerInfo(listener) != null;
+    }
+
+    @GuardedBy("mStateListenerLock")
+    private @Nullable StateListenerInfo getStateListenerInfo(
+            OnSpatializerStateChangedListener listener) {
+        if (mStateListeners == null) {
+            return null;
+        }
+        for (StateListenerInfo info : mStateListeners) {
+            if (info.mListener == listener) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    @GuardedBy("mStateListenerLock")
+    /**
+     * @return true if the listener was removed from the list
+     */
+    private boolean removeStateListener(OnSpatializerStateChangedListener listener) {
+        final StateListenerInfo infoToRemove = getStateListenerInfo(listener);
+        if (infoToRemove != null) {
+            mStateListeners.remove(infoToRemove);
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
new file mode 100644
index 0000000..f96ba8c
--- /dev/null
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -0,0 +1,407 @@
+/*
+ * 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.media.audio.common;
+
+import android.annotation.NonNull;
+import android.media.AudioFormat;
+import android.media.MediaFormat;
+import android.os.Parcel;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * This class provides utility functions for converting between
+ * the AIDL types defined in 'android.media.audio.common' and:
+ *  - SDK (Java API) types from 'android.media';
+ *  - legacy native (system/audio.h) types.
+ *
+ * Methods that convert between AIDL and SDK types are called
+ * using the following pattern:
+ *
+ *  aidl2api_AIDL-type-name_SDK-type-name
+ *  api2aidl_SDK-type-name_AIDL-type-name
+ *
+ * Since the range of the SDK values is generally narrower than
+ * the range of AIDL values, when a match can't be found, the
+ * conversion function returns a corresponding 'INVALID' value.
+ *
+ * Methods that convert between AIDL and legacy types are called
+ * using the following pattern:
+ *
+ *  aidl2legacy_AIDL-type-name_native-type-name
+ *  legacy2aidl_native-type-name_AIDL-type-name
+ *
+ * In general, there is a 1:1 mapping between AIDL and framework
+ * types, and a failure to convert a value indicates a programming
+ * error. Thus, the conversion functions may throw an IllegalArgumentException.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AidlConversion {
+    /** Convert from AIDL AudioChannelLayout to legacy audio_channel_mask_t. */
+    public static int /*audio_channel_mask_t*/ aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+            @NonNull AudioChannelLayout aidl, boolean isInput) {
+        Parcel out = Parcel.obtain();
+        aidl.writeToParcel(out, 0);
+        out.setDataPosition(0);
+        try {
+            return aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(out, isInput);
+        } finally {
+            out.recycle();
+        }
+    }
+
+    /** Convert from legacy audio_channel_mask_t to AIDL AudioChannelLayout. */
+    public static AudioChannelLayout legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+            int /*audio_channel_mask_t*/ legacy, boolean isInput) {
+        Parcel in = legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(legacy, isInput);
+        if (in != null) {
+            try {
+                return AudioChannelLayout.CREATOR.createFromParcel(in);
+            } finally {
+                in.recycle();
+            }
+        }
+        throw new IllegalArgumentException("Failed to convert legacy audio "
+                + (isInput ? "input" : "output") + " audio_channel_mask_t " + legacy + " value");
+    }
+
+    /** Convert from AIDL AudioFormatDescription to legacy audio_format_t. */
+    public static int /*audio_format_t*/ aidl2legacy_AudioFormatDescription_audio_format_t(
+            @NonNull AudioFormatDescription aidl) {
+        Parcel out = Parcel.obtain();
+        aidl.writeToParcel(out, 0);
+        out.setDataPosition(0);
+        try {
+            return aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(out);
+        } finally {
+            out.recycle();
+        }
+    }
+
+    /** Convert from legacy audio_format_t to AIDL AudioFormatDescription. */
+    public static @NonNull AudioFormatDescription legacy2aidl_audio_format_t_AudioFormatDescription(
+            int /*audio_format_t*/ legacy) {
+        Parcel in = legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(legacy);
+        if (in != null) {
+            try {
+                return AudioFormatDescription.CREATOR.createFromParcel(in);
+            } finally {
+                in.recycle();
+            }
+        }
+        throw new IllegalArgumentException(
+                "Failed to convert legacy audio_format_t value " + legacy);
+    }
+
+    /** Convert from AIDL AudioEncapsulationMode to legacy audio_encapsulation_mode_t. */
+    public static native int aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(
+            int /*AudioEncapsulationMode.* */ aidl);
+
+    /** Convert from legacy audio_encapsulation_mode_t to AIDL AudioEncapsulationMode. */
+    public static native int legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(
+            int /*audio_encapsulation_mode_t*/ legacy);
+
+    /** Convert from AIDL AudioStreamType to legacy audio_stream_type_t. */
+    public static native int aidl2legacy_AudioStreamType_audio_stream_type_t(
+            int /*AudioStreamType.* */ aidl);
+
+    /** Convert from legacy audio_stream_type_t to AIDL AudioStreamType. */
+    public static native int legacy2aidl_audio_stream_type_t_AudioStreamType(
+            int /*audio_stream_type_t*/ legacy);
+
+    /** Convert from AIDL AudioUsage to legacy audio_usage_t. */
+    public static native int aidl2legacy_AudioUsage_audio_usage_t(int /*AudioUsage.* */ aidl);
+
+    /** Convert from legacy audio_usage_t to AIDL AudioUsage. */
+    public static native int legacy2aidl_audio_usage_t_AudioUsage(int /*audio_usage_t*/ legacy);
+
+    /** Convert from AIDL AudioChannelLayout to SDK AudioFormat.CHANNEL_*. */
+    public static int aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+            @NonNull AudioChannelLayout aidlMask, boolean isInput) {
+        switch (aidlMask.getTag()) {
+            case AudioChannelLayout.none:
+                return isInput ? AudioFormat.CHANNEL_IN_DEFAULT : AudioFormat.CHANNEL_OUT_DEFAULT;
+            case AudioChannelLayout.invalid:
+                return AudioFormat.CHANNEL_INVALID;
+            case AudioChannelLayout.indexMask:
+                // Note that for a proper building of SDK AudioFormat one must
+                // call either 'setChannelMask' or 'setChannelIndexMask' depending
+                // on the variant of AudioChannelLayout. The integer representations
+                // of positional and indexed channel masks are indistinguishable in
+                // the SDK.
+                return aidlMask.getIndexMask();
+            case AudioChannelLayout.layoutMask:
+                if (isInput) {
+                    switch (aidlMask.getLayoutMask()) {
+                        case AudioChannelLayout.LAYOUT_MONO:
+                            return AudioFormat.CHANNEL_IN_MONO;
+                        case AudioChannelLayout.LAYOUT_STEREO:
+                            return AudioFormat.CHANNEL_IN_STEREO;
+                        case AudioChannelLayout.LAYOUT_FRONT_BACK:
+                            return AudioFormat.CHANNEL_IN_FRONT_BACK;
+                        default:
+                            return AudioFormat.CHANNEL_INVALID;
+                    }
+                } else {
+                    switch (aidlMask.getLayoutMask()) {
+                        case AudioChannelLayout.LAYOUT_MONO:
+                            return AudioFormat.CHANNEL_OUT_MONO;
+                        case AudioChannelLayout.LAYOUT_STEREO:
+                            return AudioFormat.CHANNEL_OUT_STEREO;
+                        case AudioChannelLayout.LAYOUT_2POINT1:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_LOW_FREQUENCY;
+                        case AudioChannelLayout.LAYOUT_TRI:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
+                        case AudioChannelLayout.LAYOUT_TRI_BACK:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_BACK_CENTER;
+                        case AudioChannelLayout.LAYOUT_3POINT1:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_CENTER
+                                    | AudioFormat.CHANNEL_OUT_LOW_FREQUENCY;
+                        case AudioChannelLayout.LAYOUT_2POINT0POINT2:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT;
+                        case AudioChannelLayout.LAYOUT_2POINT1POINT2:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_LOW_FREQUENCY;
+                        case AudioChannelLayout.LAYOUT_3POINT0POINT2:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_CENTER
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT;
+                        case AudioChannelLayout.LAYOUT_3POINT1POINT2:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_CENTER
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT
+                                    | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_LOW_FREQUENCY;
+                        case AudioChannelLayout.LAYOUT_QUAD:
+                            return AudioFormat.CHANNEL_OUT_QUAD;
+                        case AudioChannelLayout.LAYOUT_QUAD_SIDE:
+                            return AudioFormat.CHANNEL_OUT_QUAD_SIDE;
+                        case AudioChannelLayout.LAYOUT_SURROUND:
+                            return AudioFormat.CHANNEL_OUT_SURROUND;
+                        case AudioChannelLayout.LAYOUT_PENTA:
+                            return AudioFormat.CHANNEL_OUT_QUAD
+                                    | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
+                        case AudioChannelLayout.LAYOUT_5POINT1:
+                            return AudioFormat.CHANNEL_OUT_5POINT1;
+                        case AudioChannelLayout.LAYOUT_5POINT1_SIDE:
+                            return AudioFormat.CHANNEL_OUT_5POINT1_SIDE;
+                        case AudioChannelLayout.LAYOUT_5POINT1POINT2:
+                            return AudioFormat.CHANNEL_OUT_5POINT1POINT2;
+                        case AudioChannelLayout.LAYOUT_5POINT1POINT4:
+                            return AudioFormat.CHANNEL_OUT_5POINT1POINT4;
+                        case AudioChannelLayout.LAYOUT_6POINT1:
+                            return AudioFormat.CHANNEL_OUT_FRONT_LEFT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_FRONT_CENTER
+                                    | AudioFormat.CHANNEL_OUT_LOW_FREQUENCY
+                                    | AudioFormat.CHANNEL_OUT_BACK_LEFT
+                                    | AudioFormat.CHANNEL_OUT_BACK_RIGHT
+                                    | AudioFormat.CHANNEL_OUT_BACK_CENTER;
+                        case AudioChannelLayout.LAYOUT_7POINT1:
+                            return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
+                        case AudioChannelLayout.LAYOUT_7POINT1POINT2:
+                            return AudioFormat.CHANNEL_OUT_7POINT1POINT2;
+                        case AudioChannelLayout.LAYOUT_7POINT1POINT4:
+                            return AudioFormat.CHANNEL_OUT_7POINT1POINT4;
+                        case AudioChannelLayout.LAYOUT_9POINT1POINT4:
+                            return AudioFormat.CHANNEL_OUT_9POINT1POINT4;
+                        case AudioChannelLayout.LAYOUT_9POINT1POINT6:
+                            return AudioFormat.CHANNEL_OUT_9POINT1POINT6;
+                        case AudioChannelLayout.LAYOUT_13POINT_360RA:
+                            return AudioFormat.CHANNEL_OUT_13POINT_360RA;
+                        case AudioChannelLayout.LAYOUT_22POINT2:
+                            return AudioFormat.CHANNEL_OUT_22POINT2;
+                        case AudioChannelLayout.LAYOUT_MONO_HAPTIC_A:
+                            return AudioFormat.CHANNEL_OUT_MONO
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_A;
+                        case AudioChannelLayout.LAYOUT_STEREO_HAPTIC_A:
+                            return AudioFormat.CHANNEL_OUT_STEREO
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_A;
+                        case AudioChannelLayout.LAYOUT_HAPTIC_AB:
+                            return AudioFormat.CHANNEL_OUT_HAPTIC_A
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_B;
+                        case AudioChannelLayout.LAYOUT_MONO_HAPTIC_AB:
+                            return AudioFormat.CHANNEL_OUT_MONO
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_A
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_B;
+                        case AudioChannelLayout.LAYOUT_STEREO_HAPTIC_AB:
+                            return AudioFormat.CHANNEL_OUT_STEREO
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_A
+                                    | AudioFormat.CHANNEL_OUT_HAPTIC_B;
+                        case AudioChannelLayout.LAYOUT_FRONT_BACK:
+                            return AudioFormat.CHANNEL_OUT_FRONT_CENTER
+                                    | AudioFormat.CHANNEL_OUT_BACK_CENTER;
+                        default:
+                            return AudioFormat.CHANNEL_INVALID;
+                    }
+                }
+            case AudioChannelLayout.voiceMask:
+                if (isInput) {
+                    switch (aidlMask.getVoiceMask()) {
+                        // AudioFormat input masks match legacy native masks directly,
+                        // thus we add AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO here.
+                        case AudioChannelLayout.VOICE_UPLINK_MONO:
+                            return AudioFormat.CHANNEL_IN_VOICE_UPLINK
+                                    | AudioFormat.CHANNEL_IN_MONO;
+                        case AudioChannelLayout.VOICE_DNLINK_MONO:
+                            return AudioFormat.CHANNEL_IN_VOICE_DNLINK
+                                    | AudioFormat.CHANNEL_IN_MONO;
+                        case AudioChannelLayout.VOICE_CALL_MONO:
+                            return AudioFormat.CHANNEL_IN_VOICE_UPLINK
+                                    | AudioFormat.CHANNEL_IN_VOICE_DNLINK
+                                    | AudioFormat.CHANNEL_IN_MONO;
+                    }
+                }
+                return AudioFormat.CHANNEL_INVALID;
+            default:
+                return AudioFormat.CHANNEL_INVALID;
+        }
+    }
+
+    /** Convert from AIDL AudioConfig to SDK AudioFormat. */
+    public static @NonNull AudioFormat aidl2api_AudioConfig_AudioFormat(
+            @NonNull AudioConfig aidl, boolean isInput) {
+        // Only information from the encapsulated AudioConfigBase is used.
+        return aidl2api_AudioConfigBase_AudioFormat(aidl.base, isInput);
+    }
+
+    /** Convert from AIDL AudioConfigBase to SDK AudioFormat. */
+    public static @NonNull AudioFormat aidl2api_AudioConfigBase_AudioFormat(
+            @NonNull AudioConfigBase aidl, boolean isInput) {
+        AudioFormat.Builder apiBuilder = new AudioFormat.Builder();
+        apiBuilder.setSampleRate(aidl.sampleRate);
+        if (aidl.channelMask.getTag() != AudioChannelLayout.indexMask) {
+            apiBuilder.setChannelMask(aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                            aidl.channelMask, isInput));
+        } else {
+            apiBuilder.setChannelIndexMask(aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                            aidl.channelMask, isInput));
+        }
+        apiBuilder.setEncoding(aidl2api_AudioFormat_AudioFormatEncoding(aidl.format));
+        return apiBuilder.build();
+    }
+
+    /** Convert from AIDL AudioFormat to SDK AudioFormat.ENCODING_*. */
+    public static int aidl2api_AudioFormat_AudioFormatEncoding(
+            @NonNull AudioFormatDescription aidl) {
+        switch (aidl.type) {
+            case AudioFormatType.PCM:
+                switch (aidl.pcm) {
+                    case PcmType.UINT_8_BIT:
+                        return AudioFormat.ENCODING_PCM_8BIT;
+                    case PcmType.INT_16_BIT:
+                        return AudioFormat.ENCODING_PCM_16BIT;
+                    case PcmType.INT_32_BIT:
+                        return AudioFormat.ENCODING_PCM_32BIT;
+                    case PcmType.FIXED_Q_8_24:
+                    case PcmType.FLOAT_32_BIT:
+                        return AudioFormat.ENCODING_PCM_FLOAT;
+                    case PcmType.INT_24_BIT:
+                        return AudioFormat.ENCODING_PCM_24BIT_PACKED;
+                    default:
+                        return AudioFormat.ENCODING_INVALID;
+                }
+            case AudioFormatType.NON_PCM: // same as DEFAULT
+                if (aidl.encoding != null && !aidl.encoding.isEmpty()) {
+                    if (MediaFormat.MIMETYPE_AUDIO_AC3.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AC3;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_EAC3.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_E_AC3;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_DTS.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_DTS;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_DTS_HD.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_DTS_HD;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_MPEG.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_MP3;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_AAC_LC.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AAC_LC;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_AAC_HE_V1.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AAC_HE_V1;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_AAC_HE_V2.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AAC_HE_V2;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_IEC61937.equals(aidl.encoding)
+                            && aidl.pcm == PcmType.INT_16_BIT) {
+                        return AudioFormat.ENCODING_IEC61937;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_DOLBY_TRUEHD.equals(
+                                    aidl.encoding)) {
+                        return AudioFormat.ENCODING_DOLBY_TRUEHD;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_AAC_ELD.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AAC_ELD;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_AAC_XHE.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AAC_XHE;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_AC4.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_AC4;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_EAC3_JOC.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_E_AC3_JOC;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_DOLBY_MAT.equals(aidl.encoding)
+                            || aidl.encoding.startsWith(
+                                    MediaFormat.MIMETYPE_AUDIO_DOLBY_MAT + ".")) {
+                        return AudioFormat.ENCODING_DOLBY_MAT;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_OPUS.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_OPUS;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_MPEGH_BL_L3.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_MPEGH_BL_L3;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_MPEGH_BL_L4.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_MPEGH_BL_L4;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_MPEGH_LC_L3.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_MPEGH_LC_L3;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_MPEGH_LC_L4.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_MPEGH_LC_L4;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_DTS_UHD.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_DTS_UHD;
+                    } else if (MediaFormat.MIMETYPE_AUDIO_DRA.equals(aidl.encoding)) {
+                        return AudioFormat.ENCODING_DRA;
+                    } else {
+                        return AudioFormat.ENCODING_INVALID;
+                    }
+                } else {
+                    return AudioFormat.ENCODING_DEFAULT;
+                }
+            case AudioFormatType.SYS_RESERVED_INVALID:
+            default:
+                return AudioFormat.ENCODING_INVALID;
+        }
+    }
+
+    private static native int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(
+            Parcel aidl, boolean isInput);
+    private static native Parcel legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
+            int legacy, boolean isInput);
+    private static native int aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(
+            Parcel aidl);
+    private static native Parcel legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(
+            int legacy);
+}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index fbd2d8d..8080aad 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -113,10 +113,12 @@
      */
     public static final int MIX_TYPE_INVALID = -1;
     /**
+     * @hide
      * Mix type indicating playback streams are mixed.
      */
     public static final int MIX_TYPE_PLAYERS = 0;
     /**
+     * @hide
      * Mix type indicating recording streams are mixed.
      */
     public static final int MIX_TYPE_RECORDERS = 1;
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 99ddff2..fa3dc72 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -203,17 +203,34 @@
     }
 
     private final int mTargetMixType;
-
-    /** @hide */
-    @IntDef({AudioMix.MIX_TYPE_PLAYERS, AudioMix.MIX_TYPE_RECORDERS})
-    @Retention(SOURCE)
-    public @interface MixType {}
+    int getTargetMixType() {
+        return mTargetMixType;
+    }
 
     /**
-     * Gets target mix type of the mixing rule.
+     * Captures an audio signal from one or more playback streams.
      */
-    public @MixType int getTargetMixType() {
-        return mTargetMixType;
+    public static final int MIX_ROLE_PLAYERS = AudioMix.MIX_TYPE_PLAYERS;
+    /**
+     * Injects an audio signal into the framework to replace a recording source.
+     */
+    public static final int MIX_ROLE_INJECTOR = AudioMix.MIX_TYPE_RECORDERS;
+
+    /** @hide */
+    @IntDef({MIX_ROLE_PLAYERS, MIX_ROLE_INJECTOR})
+    @Retention(SOURCE)
+    public @interface MixRole {}
+
+    /**
+     * Gets target mix role of this mixing rule.
+     *
+     * <p>The mix role indicates playback streams will be captured or recording source will be
+     * injected.
+     *
+     * @return integer value of {@link #MIX_ROLE_PLAYERS} or {@link #MIX_ROLE_INJECTOR}
+     */
+    public @MixRole int getTargetMixRole() {
+        return mTargetMixType == AudioMix.MIX_TYPE_RECORDERS ? MIX_ROLE_INJECTOR : MIX_ROLE_PLAYERS;
     }
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -485,26 +502,23 @@
         }
 
         /**
-         * Sets target mix type of the mixing rule.
+         * Sets target mix role of the mixing rule.
          *
-         * <p>Note: If the mix type was not specified, it will be decided automatically by matched
-         * mixing rule. For example, {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE} or {@link
-         * AudioMixingRule#RULE_MATCH_USERID} applied {@link AudioMix#MIX_TYPE_PLAYERS}, {@link
-         * AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} applied {@link
-         * AudioMix#MIX_TYPE_RECORDERS}. For {@link AudioMixingRule#RULE_MATCH_UID}, the mix type
-         * could be {@link AudioMix#MIX_TYPE_PLAYERS} or {@link AudioMix#MIX_TYPE_RECORDERS}, and
-         * {@link AudioMix#MIX_TYPE_PLAYERS} is the default value.
+         * <p>The mix role indicates playback streams will be captured or recording source will be
+         * injected. If not specified, the mix role will be decided automatically when
+         * {@link #addRule(AudioAttributes, int)} or {@link #addMixRule(int, Object)} be called.
          *
-         * @param mixType {@link AudioMix#MIX_TYPE_PLAYERS} or {@link AudioMix#MIX_TYPE_RECORDERS}
+         * @param mixRole integer value of {@link #MIX_ROLE_PLAYERS} or {@link #MIX_ROLE_INJECTOR}
          * @return the same Builder instance.
          */
-        public @NonNull Builder setTargetMixType(@MixType int mixType) {
-            if (mixType != AudioMix.MIX_TYPE_PLAYERS && mixType != AudioMix.MIX_TYPE_RECORDERS) {
-                throw new IllegalArgumentException("Illegal argument for mix type");
+        public @NonNull Builder setTargetMixRole(@MixRole int mixRole) {
+            if (mixRole != MIX_ROLE_PLAYERS && mixRole != MIX_ROLE_INJECTOR) {
+                throw new IllegalArgumentException("Illegal argument for mix role");
             }
 
-            mTargetMixType = mixType;
-            Log.i("AudioMixingRule", "Builder setTargetMixType " + mixType);
+            Log.i("AudioMixingRule", "Builder setTargetMixRole " + mixRole);
+            mTargetMixType = mixRole == MIX_ROLE_INJECTOR
+                    ? AudioMix.MIX_TYPE_RECORDERS : AudioMix.MIX_TYPE_PLAYERS;
             return this;
         }
 
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 346edc3..f3731b6 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -101,7 +101,7 @@
             // write voice communication capture allowed flag
             dest.writeBoolean(mix.getRule().voiceCommunicationCaptureAllowed());
             // write specified mix type
-            dest.writeInt(mix.getRule().getTargetMixType());
+            dest.writeInt(mix.getRule().getTargetMixRole());
             // write mix rules
             final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             dest.writeInt(criteria.size());
@@ -137,7 +137,7 @@
             // read voice capture allowed flag
             ruleBuilder.voiceCommunicationCaptureAllowed(in.readBoolean());
             // read specified mix type
-            ruleBuilder.setTargetMixType(in.readInt());
+            ruleBuilder.setTargetMixRole(in.readInt());
             // read mix rules
             int nbRules = in.readInt();
             for (int j = 0 ; j < nbRules ; j++) {
@@ -181,7 +181,7 @@
                     + mix.getRule().voiceCommunicationCaptureAllowed() + "\n";
             // write mix rules
             textDump += "  specified mix type="
-                    + mix.getRule().getTargetMixType() + "\n";
+                    + mix.getRule().getTargetMixRole() + "\n";
             final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             for (AudioMixMatchCriterion criterion : criteria) {
                 switch(criterion.mRule) {
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 37e1415..5259c4f 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -16,15 +16,16 @@
 
 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.IBinder;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -100,19 +101,22 @@
     public VirtualDisplay createVirtualDisplay(@NonNull String name,
             int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
-        DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
         int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
                 | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
         if (isSecure) {
             flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
         }
-        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
-                height, dpi);
+        Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+                TYPE_APPLICATION, null /* options */);
+        final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
+                height, dpi, windowContext.getWindowContextToken());
         builder.setFlags(flags);
         if (surface != null) {
             builder.setSurface(surface);
         }
-        return dm.createVirtualDisplay(this, builder.build(), callback, handler);
+        VirtualDisplay virtualDisplay = createVirtualDisplay(builder.build(), callback, handler,
+                windowContext);
+        return virtualDisplay;
     }
 
     /**
@@ -141,13 +145,35 @@
     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,
-                height, dpi);
+        Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+                TYPE_APPLICATION, null /* options */);
+        final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
+                height, dpi, windowContext.getWindowContextToken());
         builder.setFlags(flags);
         if (surface != null) {
             builder.setSurface(surface);
         }
-        return createVirtualDisplay(builder.build(), callback, handler);
+        VirtualDisplay virtualDisplay = createVirtualDisplay(builder.build(), callback, handler,
+                windowContext);
+        return virtualDisplay;
+    }
+
+    /**
+     * 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, IBinder windowContextToken) {
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+                height, dpi);
+        builder.setWindowTokenClientToMirror(windowContextToken);
+        return builder;
     }
 
     /**
@@ -156,20 +182,22 @@
      *
      * @param virtualDisplayConfig The arguments for the virtual display configuration. See
      * {@link VirtualDisplayConfig} for using it.
-     * @param callback Callback to call when the virtual display's state
-     * changes, or null if none.
-     * @param handler The {@link android.os.Handler} on which the callback should be
-     * invoked, or null if the callback should be invoked on the calling
-     * thread's main {@link android.os.Looper}.
+     * @param callback Callback to call when the virtual display's state changes, or null if none.
+     * @param handler The {@link android.os.Handler} on which the callback should be invoked, or
+     *                null if the callback should be invoked on the calling thread's main
+     *                {@link android.os.Looper}.
+     * @param windowContext the WindowContext associated with the caller.
      *
      * @see android.hardware.display.VirtualDisplay
      * @hide
      */
     @Nullable
     public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
-            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
+            Context windowContext) {
         DisplayManager dm = mContext.getSystemService(DisplayManager.class);
-        return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler);
+        return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler,
+                windowContext);
     }
 
     /**
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 3b0f577..207ccbe 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(String packageName);
+    String getMediaKeyEventSessionPackageName(String packageName);
     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,
+            String packageName);
     void removeOnMediaKeyEventSessionChangedListener(
             in IOnMediaKeyEventSessionChangedListener listener);
     void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 0d506f0..728424e 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -26,6 +26,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
+import android.media.MediaCommunicationManager;
 import android.media.MediaMetadata;
 import android.media.MediaMetadataEditor;
 import android.media.MediaMetadataRetriever;
@@ -53,6 +54,7 @@
 
     private Context mContext;
     private MediaSessionManager mSessionManager;
+    private MediaCommunicationManager mCommunicationManager;
     private Handler mHandler = new Handler(Looper.getMainLooper());
     // The legacy APIs use PendingIntents to register/unregister media button
     // receivers and these are associated with RCC.
@@ -63,6 +65,7 @@
         mContext = context;
         mSessionManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
+        mCommunicationManager = context.getSystemService(MediaCommunicationManager.class);
     }
 
     @UnsupportedAppUsage
@@ -171,7 +174,7 @@
             Log.w(TAG, "Tried to send a null key event. Ignoring.");
             return;
         }
-        mSessionManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        mCommunicationManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
         if (DEBUG) {
             Log.d(TAG, "dispatched media key " + keyEvent);
         }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 269b70b..bf264f8f 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -196,16 +196,19 @@
 
     /**
      * Gets the media key event session, which would receive a media key event unless specified.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL}
+     * permission be held by the calling app, or the app has an enabled notification listener
+     * using the {@link NotificationListenerService} APIs. If none of them applies, it will throw
+     * a {@link SecurityException}.
+     *
      * @return The media key event session, which would receive key events by default, unless
      *          the caller has specified the target. Can be {@code null}.
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
     @Nullable
     public MediaSession.Token getMediaKeyEventSession() {
         try {
-            return mService.getMediaKeyEventSession();
+            return mService.getMediaKeyEventSession(mContext.getPackageName());
         } catch (RemoteException ex) {
             Log.e(TAG, "Failed to get media key event session", ex);
         }
@@ -214,20 +217,25 @@
 
     /**
      * Gets the package name of the media key event session.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL}
+     * permission be held by the calling app, or the app has an enabled notification listener
+     * using the {@link NotificationListenerService} APIs. If none of them applies, it will throw
+     * a {@link SecurityException}.
+     *
      * @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}.
+     *          receiver if the media key event session is {@code null}. Returns an empty string
+     *          if neither of them exists.
      * @see #getMediaKeyEventSession()
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
     @NonNull
     public String getMediaKeyEventSessionPackageName() {
         try {
-            String packageName = mService.getMediaKeyEventSessionPackageName();
+            String packageName = mService.getMediaKeyEventSessionPackageName(
+                    mContext.getPackageName());
             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 "";
     }
@@ -599,7 +607,7 @@
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public void dispatchMediaKeyEventAsSystemService(@NonNull KeyEvent keyEvent) {
-        dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/true, /*needWakeLock=*/false);
+        dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/true, /*needWakeLock=*/true);
     }
 
     private void dispatchMediaKeyEventInternal(KeyEvent keyEvent, boolean asSystemService,
@@ -894,14 +902,16 @@
     }
 
     /**
-     * Add a {@link OnMediaKeyEventSessionChangedListener}.
+     * Add a listener to be notified when the media key session is changed.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL}
+     * permission be held by the calling app, or the app has an enabled notification listener
+     * using the {@link NotificationListenerService} APIs. If none of them applies, it will throw
+     * a {@link SecurityException}.
      *
-     * @param executor The executor on which the listener should be invoked
+     * @param executor The executor on which the listener should be invoked.
      * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
     public void addOnMediaKeyEventSessionChangedListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnMediaKeyEventSessionChangedListener listener) {
@@ -909,40 +919,37 @@
         Objects.requireNonNull(listener, "listener shouldn't be null");
         synchronized (mLock) {
             try {
+                if (mMediaKeyEventSessionChangedCallbacks.isEmpty()) {
+                    mService.addOnMediaKeyEventSessionChangedListener(
+                            mOnMediaKeyEventSessionChangedListenerStub, mContext.getPackageName());
+                }
                 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 +1131,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 0037b53..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";
 
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index a384bef..b4ae1fb 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;
@@ -51,7 +53,6 @@
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
 import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
@@ -85,19 +86,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 +114,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 +124,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 +135,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 +144,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 +171,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 +180,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 +205,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 +254,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 {
@@ -356,7 +353,7 @@
         profile.tvInputSessionId = tvInputSessionId;
         profile.useCase = useCase;
         mTunerResourceManager.registerClientProfile(
-                profile, new HandlerExecutor(mHandler), mResourceListener, clientId);
+                profile, Runnable::run, mResourceListener, clientId);
         mClientId = clientId[0];
 
         mUserId = Process.myUid();
@@ -1148,13 +1145,13 @@
         }
     }
 
-    private void onFrequenciesReport(int[] frequency) {
+    private void onFrequenciesReport(long[] frequencies) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
                 mScanCallbackExecutor.execute(() -> {
                     synchronized (mScanCallbackLock) {
                         if (mScanCallback != null) {
-                            mScanCallback.onFrequenciesReported(frequency);
+                            mScanCallback.onFrequenciesLongReported(frequencies);
                         }
                     }
                 });
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 6c2b9e3..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";
 
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 3db7047..bd860d9 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";
 
@@ -332,6 +333,7 @@
     /**
      * Gets the filter Id in 32-bit. For any Tuner SoC that supports 64-bit filter architecture,
      * use {@link #getIdLong()}.
+     * @deprecated Use {@link #getIdLong()} for both 32-bit and 64-bit filter architectures.
      */
     public int getId() {
         synchronized (mLock) {
@@ -341,8 +343,7 @@
     }
 
     /**
-     * Gets the 64-bit filter Id. For any Tuner SoC that supports 32-bit filter architecture,
-     * use {@link #getId()}.
+     * Gets the filter Id.
      */
     public long getIdLong() {
         synchronized (mLock) {
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..e0405ef 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;
@@ -230,7 +229,7 @@
         return new Builder();
     }
 
-    private AnalogFrontendSettings(int frequency, int signalType, int sifStandard, int aftFlag) {
+    private AnalogFrontendSettings(long frequency, int signalType, int sifStandard, int aftFlag) {
         super(frequency);
         mSignalType = signalType;
         mSifStandard = sifStandard;
@@ -241,7 +240,7 @@
      * Builder for {@link AnalogFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mSignalType = SIGNAL_TYPE_UNDEFINED;
         private int mSifStandard = SIF_UNDEFINED;
         private int mAftFlag = AFT_FLAG_UNDEFINED;
@@ -252,10 +251,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index ed1ce2d..a7157e2 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,24 +260,24 @@
      * 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;
     private final Atsc3PlpSettings[] mPlpSettings;
 
-    private Atsc3FrontendSettings(int frequency, int bandwidth, int demodOutputFormat,
-            Atsc3PlpSettings[] plpSettings) {
+    private Atsc3FrontendSettings(
+            long frequency, int bandwidth, int demodOutputFormat, Atsc3PlpSettings[] plpSettings) {
         super(frequency);
         mBandwidth = bandwidth;
         mDemodOutputFormat = demodOutputFormat;
@@ -321,7 +319,7 @@
      * Builder for {@link Atsc3FrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mBandwidth = BANDWIDTH_UNDEFINED;
         private int mDemodOutputFormat = DEMOD_OUTPUT_FORMAT_UNDEFINED;
         private Atsc3PlpSettings[] mPlpSettings = {};
@@ -333,10 +331,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
index f7244bb..3071ce8 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,24 +44,24 @@
     /**
      * 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;
 
-    private AtscFrontendSettings(int frequency, int modulation) {
+    private AtscFrontendSettings(long frequency, int modulation) {
         super(frequency);
         mModulation = modulation;
     }
@@ -86,7 +86,7 @@
      * Builder for {@link AtscFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mModulation = MODULATION_UNDEFINED;
 
         private Builder() {
@@ -96,10 +96,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
index c1d0833..91102d4 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;
@@ -263,7 +247,7 @@
     private final int mGuardInterval;
     private final int mTimeInterleaveMode;
 
-    private DtmbFrontendSettings(int frequency, int modulation, int codeRate, int transmissionMode,
+    private DtmbFrontendSettings(long frequency, int modulation, int codeRate, int transmissionMode,
             int guardInterval, int timeInterleaveMode, int bandwidth) {
         super(frequency);
         mModulation = modulation;
@@ -335,7 +319,7 @@
      * Builder for {@link AtscFrontendSettings}.
      */
     public static final class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mModulation = MODULATION_CONSTELLATION_UNDEFINED;
         private int mCodeRate = CODERATE_UNDEFINED;
         private int mTransmissionMode = TRANSMISSION_MODE_UNDEFINED;
@@ -350,11 +334,24 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
+         */
+        @NonNull
+        @IntRange(from = 1)
+        @Deprecated
+        public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
         @SuppressLint("MissingGetterMatchingBuilder")
-        public Builder setFrequency(int frequency) {
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index db28631..afe953d 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;
@@ -269,7 +266,7 @@
     // Dvbc bandwidth is only supported in Tuner 1.1 or higher.
     private final int mBandwidth;
 
-    private DvbcFrontendSettings(int frequency, int modulation, long innerFec, int symbolRate,
+    private DvbcFrontendSettings(long frequency, int modulation, long innerFec, int symbolRate,
             int outerFec, int annex, int spectralInversion, int interleaveMode, int bandwidth) {
         super(frequency);
         mModulation = modulation;
@@ -350,7 +347,7 @@
      * Builder for {@link DvbcFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mModulation = MODULATION_UNDEFINED;
         private long mInnerFec = FEC_UNDEFINED;
         private int mSymbolRate = 0;
@@ -367,10 +364,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index f68d554..e16f192 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;
@@ -263,7 +263,7 @@
     // isDiseqcRxMessage is only supported in Tuner 1.1 or higher.
     private final boolean mIsDiseqcRxMessage;
 
-    private DvbsFrontendSettings(int frequency, int modulation, DvbsCodeRate codeRate,
+    private DvbsFrontendSettings(long frequency, int modulation, DvbsCodeRate codeRate,
             int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm,
             int scanType, boolean isDiseqcRxMessage) {
         super(frequency);
@@ -363,7 +363,7 @@
      * Builder for {@link DvbsFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mModulation = MODULATION_UNDEFINED;
         private DvbsCodeRate mCodeRate = null;
         private int mSymbolRate = 0;
@@ -382,10 +382,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index 536c7b8..d86e9a8 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;
@@ -418,7 +399,7 @@
     private final int mPlpId;
     private final int mPlpGroupId;
 
-    private DvbtFrontendSettings(int frequency, int transmissionMode, int bandwidth,
+    private DvbtFrontendSettings(long frequency, int transmissionMode, int bandwidth,
             int constellation, int hierarchy, int hpCodeRate, int lpCodeRate, int guardInterval,
             boolean isHighPriority, int standard, boolean isMiso, int plpMode, int plpId,
             int plpGroupId) {
@@ -551,7 +532,7 @@
      * Builder for {@link DvbtFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mTransmissionMode = TRANSMISSION_MODE_UNDEFINED;
         private int mBandwidth = BANDWIDTH_UNDEFINED;
         private int mConstellation = CONSTELLATION_UNDEFINED;
@@ -573,10 +554,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index e96cae6..5cabb71 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -34,15 +34,15 @@
 public class FrontendInfo {
     private final int mId;
     private final int mType;
-    private final Range<Integer> mFrequencyRange;
+    private final Range<Long> mFrequencyRange;
     private final Range<Integer> mSymbolRateRange;
-    private final int mAcquireRange;
+    private final long mAcquireRange;
     private final int mExclusiveGroupId;
     private final int[] mStatusCaps;
     private final FrontendCapabilities mFrontendCap;
 
-    private FrontendInfo(int id, int type, int minFrequency, int maxFrequency, int minSymbolRate,
-            int maxSymbolRate, int acquireRange, int exclusiveGroupId, int[] statusCaps,
+    private FrontendInfo(int id, int type, long minFrequency, long maxFrequency, int minSymbolRate,
+            int maxSymbolRate, long acquireRange, int exclusiveGroupId, int[] statusCaps,
             FrontendCapabilities frontendCap) {
         mId = id;
         mType = type;
@@ -77,9 +77,21 @@
 
     /**
      * Gets supported frequency range in Hz.
+     *
+     * @deprecated Use {@link #getFrequencyRangeLong()}
      */
+    @Deprecated
     @NonNull
     public Range<Integer> getFrequencyRange() {
+        return new Range<>(
+                (int) (long) mFrequencyRange.getLower(), (int) (long) mFrequencyRange.getUpper());
+    }
+
+    /**
+     * Gets supported frequency range in Hz.
+     */
+    @NonNull
+    public Range<Long> getFrequencyRangeLong() {
         return mFrequencyRange;
     }
 
@@ -95,10 +107,22 @@
      * Gets acquire range in Hz.
      *
      * <p>The maximum frequency difference the frontend can detect.
+     @deprecated Use {@link #getAcquireRangeLong(long)}
      */
+    @Deprecated
     public int getAcquireRange() {
+        return (int) getAcquireRangeLong();
+    }
+
+    /**
+     * Gets acquire range in Hz.
+     *
+     * <p>The maximum frequency difference the frontend can detect.
+     */
+    public long getAcquireRangeLong() {
         return mAcquireRange;
     }
+
     /**
      * Gets exclusive group ID.
      *
@@ -108,6 +132,7 @@
     public int getExclusiveGroupId() {
         return mExclusiveGroupId;
     }
+
     /**
      * Gets status capabilities.
      *
@@ -118,6 +143,7 @@
     public int[] getStatusCapabilities() {
         return mStatusCaps;
     }
+
     /**
      * Gets frontend capabilities.
      */
@@ -126,7 +152,6 @@
         return mFrontendCap;
     }
 
-
     /** @hide */
     @Override
     public boolean equals(Object o) {
@@ -139,9 +164,9 @@
         // TODO: compare FrontendCapabilities
         FrontendInfo info = (FrontendInfo) o;
         return mId == info.getId() && mType == info.getType()
-                && Objects.equals(mFrequencyRange, info.getFrequencyRange())
+                && Objects.equals(mFrequencyRange, info.getFrequencyRangeLong())
                 && Objects.equals(mSymbolRateRange, info.getSymbolRateRange())
-                && mAcquireRange == info.getAcquireRange()
+                && mAcquireRange == info.getAcquireRangeLong()
                 && mExclusiveGroupId == info.getExclusiveGroupId()
                 && Arrays.equals(mStatusCaps, info.getStatusCapabilities());
     }
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 4bfe807..38bffec 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,29 +259,25 @@
      * 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;
 
-
-
-    private final int mFrequency;
+    private final long mFrequency;
     // End frequency is only supported in Tuner 1.1 or higher.
-    private int mEndFrequency = Tuner.INVALID_FRONTEND_SETTING_FREQUENCY;
+    private long mEndFrequency = Tuner.INVALID_FRONTEND_SETTING_FREQUENCY;
     // General spectral inversion is only supported in Tuner 1.1 or higher.
     private int mSpectralInversion = FRONTEND_SPECTRAL_INVERSION_UNDEFINED;
 
-    FrontendSettings(int frequency) {
-        mFrequency = frequency;
-    }
+    FrontendSettings(long frequency) { mFrequency = frequency; }
 
     /**
      * Returns the frontend type.
@@ -292,8 +289,19 @@
      * Gets the frequency.
      *
      * @return the frequency in Hz.
+     * @deprecated Use {@link #getFrequencyLong()}
      */
+    @Deprecated
     public int getFrequency() {
+        return (int) getFrequencyLong();
+    }
+
+    /**
+     * Gets the frequency.
+     *
+     * @return the frequency in Hz.
+     */
+    public long getFrequencyLong() {
         return mFrequency;
     }
 
@@ -301,9 +309,21 @@
      * Get the end frequency.
      *
      * @return the end frequency in Hz.
+     * @deprecated Use {@link #getEndFrequencyLong()}
+     */
+    @Deprecated
+    @IntRange(from = 1)
+    public int getEndFrequency() {
+        return (int) getEndFrequencyLong();
+    }
+
+    /**
+     * Get the end frequency.
+     *
+     * @return the end frequency in Hz.
      */
     @IntRange(from = 1)
-    public int getEndFrequency() {
+    public long getEndFrequencyLong() {
         return mEndFrequency;
     }
 
@@ -343,9 +363,27 @@
      * @param endFrequency the end frequency used during blind scan. The default value is
      * {@link android.media.tv.tuner.Tuner#INVALID_FRONTEND_SETTING_FREQUENCY}.
      * @throws IllegalArgumentException if the {@code endFrequency} is not greater than 0.
+     * @deprecated Use {@link #setFrequencyLong(long)}
      */
     @IntRange(from = 1)
-    public void setEndFrequency(int endFrequency) {
+    @Deprecated
+    public void setEndFrequency(int frequency) {
+        setEndFrequencyLong((long) frequency);
+    }
+
+    /**
+     * Set End Frequency. This API is only supported with Tuner HAL 1.1 or higher. Otherwise it
+     * would be no-op.
+     *
+     * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+     * no-op. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * @param endFrequency the end frequency used during blind scan. The default value is
+     * {@link android.media.tv.tuner.Tuner#INVALID_FRONTEND_SETTING_FREQUENCY}.
+     * @throws IllegalArgumentException if the {@code endFrequency} is not greater than 0.
+     */
+    @IntRange(from = 1)
+    public void setEndFrequencyLong(long endFrequency) {
         if (TunerVersionChecker.checkHigherOrEqualVersionTo(
                 TunerVersionChecker.TUNER_VERSION_1_1, "setEndFrequency")) {
             if (endFrequency < 1) {
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index b82a5a9..53adc75 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 = {
@@ -435,7 +447,7 @@
     private Boolean mIsLnaOn;
     private boolean[] mIsLayerErrors;
     private Integer mMer;
-    private Integer mFreqOffset;
+    private Long mFreqOffset;
     private Integer mHierarchy;
     private Boolean mIsRfLocked;
     private Atsc3PlpTuningInfo[] mPlpInfo;
@@ -639,8 +651,18 @@
      * Gets the current frequency difference in Hz.
      *
      * <p>Difference between tuning frequency and actual locked frequency.
+     * @deprecated Use {@link #getFreqOffsetLong()}
      */
+    @Deprecated
     public int getFreqOffset() {
+        return (int) getFreqOffsetLong();
+    }
+    /**
+     * Gets the current frequency difference in Hz.
+     *
+     * <p>Difference between tuning frequency and actual locked frequency.
+     */
+    public long getFreqOffsetLong() {
         if (mFreqOffset == null) {
             throw new IllegalStateException("FreqOffset status is empty");
         }
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index 02cdb96..726fe15 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;
@@ -156,7 +158,7 @@
     private final int mSymbolRate;
     private final int mRolloff;
 
-    private Isdbs3FrontendSettings(int frequency, int streamId, int streamIdType, int modulation,
+    private Isdbs3FrontendSettings(long frequency, int streamId, int streamIdType, int modulation,
             int codeRate, int symbolRate, int rolloff) {
         super(frequency);
         mStreamId = streamId;
@@ -220,7 +222,7 @@
      * Builder for {@link Isdbs3FrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mStreamId = Tuner.INVALID_STREAM_ID;
         private int mStreamIdType = IsdbsFrontendSettings.STREAM_ID_TYPE_ID;
         private int mModulation = MODULATION_UNDEFINED;
@@ -235,10 +237,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index 3cc1aab..51ec5ae 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;
@@ -140,7 +143,7 @@
     private final int mSymbolRate;
     private final int mRolloff;
 
-    private IsdbsFrontendSettings(int frequency, int streamId, int streamIdType, int modulation,
+    private IsdbsFrontendSettings(long frequency, int streamId, int streamIdType, int modulation,
             int codeRate, int symbolRate, int rolloff) {
         super(frequency);
         mStreamId = streamId;
@@ -204,7 +207,7 @@
      * Builder for {@link IsdbsFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mStreamId = Tuner.INVALID_STREAM_ID;
         private int mStreamIdType = STREAM_ID_TYPE_ID;
         private int mModulation = MODULATION_UNDEFINED;
@@ -219,10 +222,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
index 6a14d08..d34b643 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;
@@ -132,7 +134,7 @@
     private final int mGuardInterval;
     private final int mServiceAreaId;
 
-    private IsdbtFrontendSettings(int frequency, int modulation, int bandwidth, int mode,
+    private IsdbtFrontendSettings(long frequency, int modulation, int bandwidth, int mode,
             int codeRate, int guardInterval, int serviceAreaId) {
         super(frequency);
         mModulation = modulation;
@@ -197,7 +199,7 @@
      * Builder for {@link IsdbtFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency = 0;
+        private long mFrequency = 0;
         private int mModulation = MODULATION_UNDEFINED;
         private int mBandwidth = BANDWIDTH_UNDEFINED;
         private int mMode = MODE_UNDEFINED;
@@ -212,10 +214,23 @@
          * Sets frequency in Hz.
          *
          * <p>Default value is 0.
+         * @deprecated Use {@link #setFrequencyLong(long)}
          */
         @NonNull
         @IntRange(from = 1)
+        @Deprecated
         public Builder setFrequency(int frequency) {
+            return setFrequencyLong((long) frequency);
+        }
+
+        /**
+         * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        @IntRange(from = 1)
+        public Builder setFrequencyLong(long frequency) {
             mFrequency = frequency;
             return this;
         }
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/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index 27627d7..f61bd52 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -37,8 +37,19 @@
     /** scan progress percent (0..100) */
     void onProgress(@IntRange(from = 0, to = 100) int percent);
 
+    /**
+     * @deprecated Use {@link #onFrequenciesLongReported(long[])}
+     */
+    @Deprecated void onFrequenciesReported(@NonNull int[] frequencies);
+
     /** Signal frequencies in Hertz */
-    void onFrequenciesReported(@NonNull int[] frequency);
+    default void onFrequenciesLongReported(@NonNull long[] frequencies) {
+        final int[] intFrequencies = new int[frequencies.length];
+        for (int i = 0; i < frequencies.length; i++) {
+              intFrequencies[i] = (int) frequencies[i];
+        }
+        onFrequenciesReported(intFrequencies);
+    }
 
     /** Symbols per second */
     void onSymbolRatesReported(@NonNull int[] rate);
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/IResourcesReclaimListener.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl
index 1a4eb29..feb68dc 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl
@@ -21,7 +21,7 @@
  *
  * @hide
  */
-oneway interface IResourcesReclaimListener {
+interface IResourcesReclaimListener {
     /*
      * TRM invokes this method when the client's resources need to be reclaimed.
      *
@@ -30,4 +30,4 @@
      * then grant the resource.
      */
     void onReclaimResources();
-}
\ No newline at end of file
+}
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/OWNERS b/media/jni/OWNERS
index f1b0237..445672b 100644
--- a/media/jni/OWNERS
+++ b/media/jni/OWNERS
@@ -2,4 +2,4 @@
 per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
 
 # extra for TV related files
-per-file android_media_tv_*=nchalko@google.com,quxiangfang@google.com
+per-file android_media_tv_*=hgchen@google.com,quxiangfang@google.com
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e4f3f33..4bee485 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,29 +371,25 @@
 }
 
 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)) {
-        env->CallVoidMethod(
-                dvr,
-                gFields.onDvrRecordStatusID,
-                (jint) status);
+        env->CallVoidMethod(dvr, gFields.onDvrRecordStatusID, (jint)status);
     } else {
         ALOGE("DvrClientCallbackImpl::onRecordStatus:"
                 "Dvr object has been freed. Ignoring callback.");
@@ -278,14 +397,11 @@
 }
 
 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)) {
-        env->CallVoidMethod(
-                dvr,
-                gFields.onDvrPlaybackStatusID,
-                (jint) status);
+        env->CallVoidMethod(dvr, gFields.onDvrPlaybackStatusID, (jint)status);
     } else {
         ALOGE("DvrClientCallbackImpl::onPlaybackStatus:"
                 "Dvr object has been freed. Ignoring callback.");
@@ -293,20 +409,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 +431,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, int64_t dataId,
+                       int64_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 +476,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 +493,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 +517,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 +532,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;
@@ -440,46 +559,39 @@
         mAvHandleRefCnt++;
         return linearBlock;
     } else {
-        native_handle_close(const_cast<native_handle_t*>(
-                    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;
+        native_handle_close(const_cast<native_handle_t *>(
+                reinterpret_cast<const native_handle_t *>(mIonHandle)));
+        native_handle_delete(const_cast<native_handle_t *>(
+                reinterpret_cast<const native_handle_t *>(mIonHandle)));
+        mIonHandle = nullptr;
+        return nullptr;
     }
 }
 
-uint64_t MediaEvent::getAudioHandle() {
+int64_t MediaEvent::getAudioHandle() {
     mDataIdRefCnt++;
     return mDataId;
 }
 
 /////////////// 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 = sectionEvent.tableId;
+    jint version = sectionEvent.version;
+    jint sectionNum = sectionEvent.sectionNum;
+    jint dataLength = 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 +600,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 = ad.adFade;
+        jbyte adPan = ad.adPan;
+        jchar versionTextTag = ad.versionTextTag;
+        jbyte adGainCenter = ad.adGainCenter;
+        jbyte adGainFront = ad.adGainFront;
+        jbyte adGainSurround = 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 = mediaEvent.dataLength;
+    jint streamId = mediaEvent.streamId;
+    jboolean isPtsPresent = mediaEvent.isPtsPresent;
+    jlong pts = mediaEvent.pts;
+    jlong offset = mediaEvent.offset;
+    jboolean isSecureMemory = mediaEvent.isSecureMemory;
+    jlong avDataId = mediaEvent.avDataId;
+    jint mpuSequenceNumber = mediaEvent.mpuSequenceNumber;
+    jboolean isPesPrivateData = mediaEvent.isPesPrivateData;
+
+    jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
+                                 offset, nullptr, isSecureMemory, avDataId, mpuSequenceNumber,
+                                 isPesPrivateData, audioDescriptor);
+
+    uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size;
+    if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 ||
+        (dataLength > 0 && (dataLength + offset) < avSharedMemSize)) {
+        sp<MediaEvent> mediaEventSp =
+                new MediaEvent(mFilterClient, dupFromAidl(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 = pesEvent.streamId;
+    jint dataLength = pesEvent.dataLength;
+    jint mpuSequenceNumber = 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 = pid.get<DemuxPid::Tag::tPid>();
+    } else if (pid.getTag() == DemuxPid::Tag::mmtpPid) {
+        jpid = pid.get<DemuxPid::Tag::mmtpPid>();
     }
-    return arr;
+
+    jint sc = 0;
+    if (tsRecordEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scIndex) {
+        sc = tsRecordEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scIndex>();
+    } else if (tsRecordEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scHevc) {
+        sc = tsRecordEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scHevc>();
+    }
+
+    jint ts = tsRecordEvent.tsIndexMask;
+    jlong byteNumber = tsRecordEvent.byteNumber;
+    jlong pts = tsRecordEvent.pts;
+    jint firstMbInSlice = 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 = mmtpRecordEvent.scHevcIndexMask;
+    jlong byteNumber = mmtpRecordEvent.byteNumber;
+    jint mpuSequenceNumber = mmtpRecordEvent.mpuSequenceNumber;
+    jlong pts = mmtpRecordEvent.pts;
+    jint firstMbInSlice = mmtpRecordEvent.firstMbInSlice;
+    jlong tsIndexMask = 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 = downloadEvent.itemId;
+    jint mpuSequenceNumber = downloadEvent.mpuSequenceNumber;
+    jint itemFragmentIndex = downloadEvent.itemFragmentIndex;
+    jint lastItemFragmentIndex = downloadEvent.lastItemFragmentIndex;
+    jint dataLength = 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 = 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 = temiEvent.pts;
+    jbyte descrTag = 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();
-    jobject obj = env->NewObject(eventClazz, eventInit, static_cast<jint>(startId));
-    env->SetObjectArrayElement(arr, 0, obj);
-    return arr;
+    const int32_t &startId = event.get<DemuxFilterEvent::Tag::startId>();
+    jobject obj = env->NewObject(eventClazz, eventInit, startId);
+    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 +889,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 +910,7 @@
 }
 
 void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filterClient) {
-    ALOGD("FilterClientCallbackImpl::setFilter");
+    ALOGV("FilterClientCallbackImpl::setFilter");
     // Java Object
     mFilterObj = filterObj;
     mFilterClient = filterClient;
@@ -884,19 +918,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 +945,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 +956,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 +964,7 @@
             break;
         }
         case FrontendScanMessageType::END: {
-            if (message.isEnd()) {
+            if (message.get<FrontendScanMessage::Tag::isEnd>()) {
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onScanStopped", "()V"));
@@ -939,211 +972,158 @@
             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"),
+                                message.get<FrontendScanMessage::Tag::progressPercent>());
             break;
         }
         case FrontendScanMessageType::FREQUENCY: {
-            std::vector<uint32_t> v = message.frequencies();
-            jintArray freqs = env->NewIntArray(v.size());
-            env->SetIntArrayRegion(freqs, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
-
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onFrequenciesReport", "([I)V"),
-                    freqs);
+            std::vector<int64_t> v = message.get<FrontendScanMessage::Tag::frequencies>();
+            jlongArray freqs = env->NewLongArray(v.size());
+            env->SetLongArrayRegion(freqs, 0, v.size(), reinterpret_cast<jlong *>(&v[0]));
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onFrequenciesReport", "([J)V"),
+                                freqs);
             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]));
-
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onSymbolRates", "([I)V"),
-                    symbolRates);
+            env->SetIntArrayRegion(symbolRates, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onSymbolRates", "([I)V"),
+                                symbolRates);
             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<jint> jintV(v.begin(), v.end());
-            jintArray plpIds = env->NewIntArray(v.size());
-            env->SetIntArrayRegion(plpIds, 0, jintV.size(), &jintV[0]);
-
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onPlpIds", "([I)V"),
-                    plpIds);
+            std::vector<int32_t> jintV = message.get<FrontendScanMessage::Tag::plpIds>();
+            jintArray plpIds = env->NewIntArray(jintV.size());
+            env->SetIntArrayRegion(plpIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onPlpIds", "([I)V"), plpIds);
             break;
         }
         case FrontendScanMessageType::GROUP_IDS: {
-            std::vector<uint8_t> v = message.groupIds();
-            std::vector<jint> jintV(v.begin(), v.end());
-            jintArray groupIds = env->NewIntArray(v.size());
-            env->SetIntArrayRegion(groupIds, 0, jintV.size(), &jintV[0]);
-
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onGroupIds", "([I)V"),
-                    groupIds);
+            std::vector<int32_t> jintV = message.get<FrontendScanMessage::groupIds>();
+            jintArray groupIds = env->NewIntArray(jintV.size());
+            env->SetIntArrayRegion(groupIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onGroupIds", "([I)V"), groupIds);
             break;
         }
         case FrontendScanMessageType::INPUT_STREAM_IDS: {
-            std::vector<uint16_t> v = message.inputStreamIds();
-            std::vector<jint> jintV(v.begin(), v.end());
-            jintArray streamIds = env->NewIntArray(v.size());
-            env->SetIntArrayRegion(streamIds, 0, jintV.size(), &jintV[0]);
-
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onInputStreamIds", "([I)V"),
-                    streamIds);
+            std::vector<int32_t> jintV = message.get<FrontendScanMessage::inputStreamIds>();
+            jintArray streamIds = env->NewIntArray(jintV.size());
+            env->SetIntArrayRegion(streamIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onInputStreamIds", "([I)V"),
+                                streamIds);
             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();
-                env->CallVoidMethod(
-                        frontend,
-                        env->GetMethodID(clazz, "onDvbsStandard", "(I)V"),
-                        standard);
-            } else if (std.getDiscriminator() ==
-                    FrontendScanMessage::Standard::hidl_discriminator::tStd) {
-                standard = (jint) std.tStd();
-                env->CallVoidMethod(
-                        frontend,
-                        env->GetMethodID(clazz, "onDvbtStandard", "(I)V"),
-                        standard);
-            } else if (std.getDiscriminator() ==
-                    FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
-                standard = (jint) std.sifStd();
-                env->CallVoidMethod(
-                        frontend,
-                        env->GetMethodID(clazz, "onAnalogSifStandard", "(I)V"),
-                        standard);
+            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.getTag() == FrontendScanMessageStandard::Tag::tStd) {
+                standard = (jint)std.get<FrontendScanMessageStandard::Tag::tStd>();
+                env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onDvbtStandard", "(I)V"),
+                                    standard);
+            } else if (std.getTag() == FrontendScanMessageStandard::Tag::sifStd) {
+                standard = (jint)std.get<FrontendScanMessageStandard::Tag::sifStd>();
+                env->CallVoidMethod(frontend,
+                                    env->GetMethodID(clazz, "onAnalogSifStandard", "(I)V"),
+                                    standard);
             }
             break;
         }
         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];
-                jint plpId = (jint) info.plpId;
-                jboolean lls = (jboolean) info.bLlsFlag;
-
+                const FrontendScanAtsc3PlpInfo &info = plpInfos[i];
+                jint plpId = info.plpId;
+                jboolean lls = info.bLlsFlag;
                 jobject obj = env->NewObject(plpClazz, init, plpId, lls);
                 env->SetObjectArrayElement(array, i, obj);
             }
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onAtsc3PlpInfos",
-                            "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"),
-                    array);
+            env->CallVoidMethod(frontend,
+                                env->GetMethodID(clazz, "onAtsc3PlpInfos",
+                                                 "([Landroid/media/tv/tuner/frontend/"
+                                                 "Atsc3PlpInfo;)V"),
+                                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();
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onPriorityReported", "(Z)V"),
-                    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();
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"),
-                    dvbcAnnex);
+        case FrontendScanMessageType::DVBC_ANNEX: {
+            jint dvbcAnnex = (jint)message.get<FrontendScanMessage::Tag::annex>();
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"),
+                                dvbcAnnex);
             break;
         }
         default:
@@ -1153,59 +1133,56 @@
 
 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;
+    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;
+    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();
@@ -1216,9 +1193,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;
 }
@@ -1226,14 +1203,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);
     }
 
@@ -1242,10 +1219,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(
@@ -1256,7 +1234,7 @@
 }
 
 int JTuner::shareFrontend(int feId) {
-    if (mFeClient != NULL) {
+    if (mFeClient != nullptr) {
         ALOGE("Cannot share frontend:%d because this session is already holding %d",
               feId, mFeClient->getId());
         return (int)Result::INVALID_STATE;
@@ -1266,127 +1244,124 @@
     return (int)Result::SUCCESS;
 }
 
-jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+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);
@@ -1395,115 +1370,105 @@
 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();
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendInfo");
-    jmethodID infoInit = env->GetMethodID(clazz, "<init>",
-            "(IIIIIIII[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V");
+    jmethodID infoInit =
+            env->GetMethodID(clazz, "<init>",
+                             "(IIJJIIJI[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V");
 
-    jint type = (jint) feInfo->type;
-    jint minFrequency = feInfo->minFrequency;
-    jint maxFrequency = feInfo->maxFrequency;
+    jint type = (jint)feInfo->type;
+    jlong minFrequency = feInfo->minFrequency;
+    jlong maxFrequency = feInfo->maxFrequency;
     jint minSymbolRate = feInfo->minSymbolRate;
     jint maxSymbolRate = feInfo->maxSymbolRate;
-    jint acquireRange = feInfo->acquireRange;
+    jlong acquireRange = feInfo->acquireRange;
     jint exclusiveGroupId = feInfo->exclusiveGroupId;
     jintArray statusCaps = env->NewIntArray(feInfo->statusCaps.size());
     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;
     }
 
-    return env->NewObject(
-            clazz, infoInit, (jint) id, type, minFrequency, maxFrequency, minSymbolRate,
-            maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
+    return env->NewObject(clazz, infoInit, id, type, minFrequency, maxFrequency, minSymbolRate,
+                          maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
 }
 
 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();
@@ -1519,8 +1484,8 @@
 }
 
 jobject JTuner::openLnbByName(jstring name) {
-    if (mTunerClient == NULL) {
-        return NULL;
+    if (mTunerClient == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1528,14 +1493,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(
@@ -1549,12 +1514,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() {
@@ -1565,18 +1530,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;
     }
@@ -1585,11 +1549,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;
     }
@@ -1598,7 +1562,7 @@
 }
 
 int JTuner::setLna(bool enable) {
-    if (mFeClient == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Result::INVALID_STATE;
     }
@@ -1613,13 +1577,13 @@
 
     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) {
+        if (mFeClient != nullptr) {
             return mDemuxClient->setFrontendDataSource(mFeClient);
-        } else if (mSharedFeId != (int) Constant::INVALID_FRONTEND_ID) {
+        } else if (mSharedFeId != (int)Constant::INVALID_FRONTEND_ID) {
             return mDemuxClient->setFrontendDataSourceById(mSharedFeId);
         }
     }
@@ -1630,28 +1594,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;
     }
 
-    mSharedFeId = (int) Constant::INVALID_FRONTEND_ID;
-    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);
@@ -1661,33 +1625,32 @@
         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) {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         jclass longClazz = env->FindClass("java/lang/Long");
         jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
-        return env->NewObject(longClazz, longInit, static_cast<jlong>(time));
+        return env->NewObject(longClazz, longInit, 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;
     }
@@ -1695,35 +1658,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);
@@ -1741,31 +1699,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, fId);
 
     filterClient->incStrong(filterObj);
     env->SetLongField(filterObj, gFields.filterContext, (jlong)filterClient.get());
@@ -1775,8 +1730,8 @@
 }
 
 jobject JTuner::openTimeFilter() {
-    if (mDemuxClient == NULL) {
-        return NULL;
+    if (mDemuxClient == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1785,9 +1740,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());
@@ -1796,16 +1751,17 @@
 }
 
 jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
-    ALOGD("JTuner::openDvr");
-    if (mDemuxClient == NULL) {
-        return NULL;
+    ALOGV("JTuner::openDvr");
+    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) {
+        ALOGD("Failed to open Dvr");
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1832,14 +1788,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();
@@ -1856,12 +1812,12 @@
     jint numPesFilter = caps->numPesFilter;
     jint numPcrFilter = caps->numPcrFilter;
     jlong numBytesInSectionFilter = caps->numBytesInSectionFilter;
-    jint filterCaps = static_cast<jint>(caps->filterCaps);
+    jint filterCaps = caps->filterCaps;
     jboolean bTimeFilter = caps->bTimeFilter;
 
     jintArray linkCaps = env->NewIntArray(caps->linkCaps.size());
-    env->SetIntArrayRegion(
-            linkCaps, 0, caps->linkCaps.size(), reinterpret_cast<jint*>(&caps->linkCaps[0]));
+    env->SetIntArrayRegion(linkCaps, 0, caps->linkCaps.size(),
+                           reinterpret_cast<jint *>(&caps->linkCaps[0]));
 
     return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter,
             numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter,
@@ -1869,25 +1825,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");
@@ -1897,98 +1847,109 @@
     jmethodID initInt = env->GetMethodID(intClazz, "<init>", "(I)V");
     jclass booleanClazz = env->FindClass("java/lang/Boolean");
     jmethodID initBoolean = env->GetMethodID(booleanClazz, "<init>", "(Z)V");
+    jclass longClazz = env->FindClass("java/lang/Long");
+    jmethodID initLong = env->GetMethodID(longClazz, "<init>", "(J)V");
 
-    for (auto s : status) {
-        switch(s.getDiscriminator()) {
-            case FrontendStatus::hidl_discriminator::isDemodLocked: {
+    for (int i = 0; i < status.size(); i++) {
+        const FrontendStatus &s = status[i];
+        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,
+                                                       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, 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, 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, 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, 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,
+                                                       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,
+                                       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, 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<long>(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: {
@@ -2002,51 +1963,53 @@
                 }
                 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, 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,
+                                                       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, 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,
+                                                       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());
 
@@ -2057,49 +2020,49 @@
                 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, s.get<FrontendStatus::Tag::mer>());
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::freqOffset: {
-                jfieldID field = env->GetFieldID(clazz, "mFreqOffset", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.freqOffset()));
-                env->SetObjectField(statusObj, field, newIntegerObj);
+            case FrontendStatus::Tag::freqOffset: {
+                jfieldID field = env->GetFieldID(clazz, "mFreqOffset", "Ljava/lang/Long;");
+                jobject newLongObj = env->NewObject(longClazz, initLong,
+                                                    s.get<FrontendStatus::Tag::freqOffset>());
+                env->SetObjectField(statusObj, field, newLongObj);
                 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,
+                                                       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;
-                    jboolean isLocked = (jboolean) info.isLocked;
-                    jint uec = (jint) info.uec;
+                    const FrontendStatusAtsc3PlpInfo &info = plpInfos[i];
+                    jint plpId = info.plpId;
+                    jboolean isLocked = info.isLocked;
+                    jint uec = info.uec;
 
                     jobject plpObj = env->NewObject(plpClazz, initPlp, plpId, isLocked, uec);
                     env->SetObjectArrayElement(valObj, i, plpObj);
@@ -2108,74 +2071,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());
+                    const FrontendModulation &modulation = v[i];
+                    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;
@@ -2189,51 +2153,55 @@
                 }
                 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]));
+                env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
 
                 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]));
+                env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
 
                 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();
+                const FrontendBandwidth &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:
@@ -2246,22 +2214,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();
+                const FrontendGuardInterval &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:
@@ -2274,22 +2245,26 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::transmissionMode: {
+            case FrontendStatus::Tag::transmissionMode: {
                 jfieldID field = env->GetFieldID(clazz, "mTransmissionMode", "Ljava/lang/Integer;");
-                auto transmissionMode = s.transmissionMode();
+                const FrontendTransmissionMode &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:
@@ -2302,44 +2277,46 @@
                 }
                 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, 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, 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());
+                    const FrontendInterleaveMode &interleaving = v[i];
+                    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;
@@ -2353,9 +2330,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<int32_t> v = s.get<FrontendStatus::Tag::isdbtSegment>();
 
                 jintArray valObj = env->NewIntArray(v.size());
                 env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
@@ -2363,32 +2340,32 @@
                 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]));
+                env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
 
                 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();
+                const FrontendRollOff &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:
@@ -2401,24 +2378,24 @@
                 }
                 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,
+                                                       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,
+                                                       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,
+                                                       s.get<FrontendStatus::Tag::isShortFrames>());
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
@@ -2430,33 +2407,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
 
@@ -2467,14 +2439,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());
     }
 
@@ -2491,26 +2463,24 @@
 
 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 int64_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));
-    return freq;
+    jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "J");
+    return env->GetLongField(settings, freqField);
 }
 
-static uint32_t getFrontendSettingsEndFreq(JNIEnv *env, const jobject& settings) {
+static int64_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));
-    return endFreq;
+    jfieldID endFreqField = env->GetFieldID(clazz, "mEndFrequency", "J");
+    return env->GetLongField(settings, endFreqField);
 }
 
 static FrontendSpectralInversion getFrontendSettingsSpectralInversion(
@@ -2524,7 +2494,9 @@
 
 static FrontendSettings getAnalogFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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>(
@@ -2532,29 +2504,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>(
@@ -2566,13 +2530,11 @@
     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")));
+        int32_t plpId = env->GetIntField(plp, env->GetFieldID(plpClazz, "mPlpId", "I"));
         FrontendAtsc3Modulation modulation =
                 static_cast<FrontendAtsc3Modulation>(
                         env->GetIntField(plp, env->GetFieldID(plpClazz, "mModulation", "I")));
@@ -2600,9 +2562,10 @@
 
 static FrontendSettings getAtsc3FrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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")));
@@ -2610,35 +2573,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);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_t endFreq = getFrontendSettingsEndFreq(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings");
     FrontendDvbcModulation modulation =
             static_cast<FrontendDvbcModulation>(
@@ -2646,49 +2616,35 @@
     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 = 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 =
@@ -2704,18 +2660,11 @@
                     env->GetLongField(
                             jcodeRate, env->GetFieldID(codeRateClazz, "mInnerFec", "J")));
     bool isLinear =
-            static_cast<bool>(
-                    env->GetBooleanField(
-                            jcodeRate, env->GetFieldID(codeRateClazz, "mIsLinear", "Z")));
+            env->GetBooleanField(jcodeRate, env->GetFieldID(codeRateClazz, "mIsLinear", "Z"));
     bool isShortFrames =
-            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")));
+            env->GetBooleanField(jcodeRate, env->GetFieldID(codeRateClazz, "mIsShortFrames", "Z"));
+    int32_t bitsPer1000Symbol =
+            env->GetIntField(jcodeRate, env->GetFieldID(codeRateClazz, "mBitsPer1000Symbol", "I"));
     FrontendDvbsCodeRate coderate {
             .fec = innerFec,
             .isLinear = isLinear,
@@ -2727,33 +2676,36 @@
 
 static FrontendSettings getDvbsFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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 = 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 =
+            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 =
+            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "Z"));
 
-    FrontendDvbsSettings frontendDvbsSettings {
+    FrontendDvbsSettings frontendDvbsSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .modulation = modulation,
             .symbolRate = symbolRate,
             .rolloff = rolloff,
@@ -2761,37 +2713,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);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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>(
@@ -2816,27 +2757,20 @@
             static_cast<FrontendDvbtGuardInterval>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mGuardInterval", "I")));
     bool isHighPriority =
-            static_cast<bool>(
-                    env->GetBooleanField(
-                            settings, env->GetFieldID(clazz, "mIsHighPriority", "Z")));
+            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsHighPriority", "Z"));
     FrontendDvbtStandard standard =
             static_cast<FrontendDvbtStandard>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mStandard", "I")));
-    bool isMiso =
-            static_cast<bool>(
-                    env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsMiso", "Z")));
+    bool isMiso = env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsMiso", "Z"));
     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")));
+    int32_t plpId = env->GetIntField(settings, env->GetFieldID(clazz, "mPlpId", "I"));
+    int32_t plpGroupId = env->GetIntField(settings, env->GetFieldID(clazz, "mPlpGroupId", "I"));
 
-    FrontendDvbtSettings frontendDvbtSettings {
+    FrontendDvbtSettings frontendDvbtSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .transmissionMode = transmissionMode,
             .bandwidth = bandwidth,
             .constellation = constellation,
@@ -2850,37 +2784,18 @@
             .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);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_t endFreq = getFrontendSettingsEndFreq(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendSettings");
-    uint16_t streamId =
-            static_cast<uint16_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I")));
+    int32_t streamId = env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I"));
     FrontendIsdbsStreamIdType streamIdType =
             static_cast<FrontendIsdbsStreamIdType>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mStreamIdType", "I")));
@@ -2890,15 +2805,14 @@
     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 = 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,
@@ -2906,17 +2820,16 @@
             .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);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_t endFreq = getFrontendSettingsEndFreq(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendSettings");
-    uint16_t streamId =
-            static_cast<uint16_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I")));
+    int32_t streamId = env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I"));
     FrontendIsdbsStreamIdType streamIdType =
             static_cast<FrontendIsdbsStreamIdType>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mStreamIdType", "I")));
@@ -2926,15 +2839,14 @@
     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 = 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,
@@ -2942,13 +2854,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);
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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>(
@@ -2965,26 +2879,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 =
+            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;
+    int64_t freq = getFrontendSettingsFreq(env, settings);
+    int64_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>(
@@ -3005,25 +2922,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:
@@ -3044,6 +2959,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
@@ -3053,64 +2970,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);
 }
@@ -3122,30 +2981,24 @@
 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 = env->GetIntField(settings, env->GetFieldID(clazz, "mStatusMask", "I"));
+    int64_t lowThreshold =
+            env->GetLongField(settings, env->GetFieldID(clazz, "mLowThreshold", "J"));
+    int64_t highThreshold =
+            env->GetLongField(settings, env->GetFieldID(clazz, "mHighThreshold", "J"));
+    int64_t packetSize = env->GetLongField(settings, env->GetFieldID(clazz, "mPacketSize", "J"));
     DataFormat dataFormat =
             static_cast<DataFormat>(env->GetIntField(
                     settings, env->GetFieldID(clazz, "mDataFormat", "I")));
     if (isRecorder) {
-        RecordSettings recordSettings {
-                .statusMask = static_cast<unsigned char>(statusMask),
+        RecordSettings recordSettings{
+                .statusMask = statusMask,
                 .lowThreshold = lowThreshold,
                 .highThreshold = highThreshold,
                 .dataFormat = dataFormat,
                 .packetSize = packetSize,
         };
-        dvrSettings.record(recordSettings);
+        dvrSettings.set<DvrSettings::Tag::record>(recordSettings);
     } else {
         PlaybackSettings PlaybackSettings {
                 .statusMask = statusMask,
@@ -3154,7 +3007,7 @@
                 .dataFormat = dataFormat,
                 .packetSize = packetSize,
         };
-        dvrSettings.playback(PlaybackSettings);
+        dvrSettings.set<DvrSettings::Tag::playback>(PlaybackSettings);
     }
     return dvrSettings;
 }
@@ -3169,10 +3022,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");
 
@@ -3255,9 +3108,7 @@
 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) {
@@ -3269,9 +3120,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) {
@@ -3282,7 +3131,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;
     }
@@ -3303,9 +3152,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);
@@ -3360,22 +3209,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,20 +3249,19 @@
             env->GetObjectField(settings, env->GetFieldID(clazz, "mFilter", "[B")));
     jsize size = env->GetArrayLength(jfilterBytes);
     std::vector<uint8_t> filterBytes(size);
-    env->GetByteArrayRegion(
-            jfilterBytes, 0, size, reinterpret_cast<jbyte*>(&filterBytes[0]));
+    env->GetByteArrayRegion(jfilterBytes, 0, size, reinterpret_cast<jbyte *>(&filterBytes[0]));
 
     jbyteArray jmask = static_cast<jbyteArray>(
             env->GetObjectField(settings, env->GetFieldID(clazz, "mMask", "[B")));
     size = env->GetArrayLength(jmask);
     std::vector<uint8_t> mask(size);
-    env->GetByteArrayRegion(jmask, 0, size, reinterpret_cast<jbyte*>(&mask[0]));
+    env->GetByteArrayRegion(jmask, 0, size, reinterpret_cast<jbyte *>(&mask[0]));
 
     jbyteArray jmode = static_cast<jbyteArray>(
             env->GetObjectField(settings, env->GetFieldID(clazz, "mMode", "[B")));
     size = env->GetArrayLength(jmode);
     std::vector<uint8_t> mode(size);
-    env->GetByteArrayRegion(jmode, 0, size, reinterpret_cast<jbyte*>(&mode[0]));
+    env->GetByteArrayRegion(jmode, 0, size, reinterpret_cast<jbyte *>(&mode[0]));
 
     DemuxFilterSectionBits filterSectionBits {
         .filter = filterBytes,
@@ -3415,28 +3271,23 @@
     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,
+    int32_t tableId = env->GetIntField(settings, env->GetFieldID(clazz, "mTableId", "I"));
+    int32_t version = env->GetIntField(settings, env->GetFieldID(clazz, "mVersion", "I"));
+    DemuxFilterSectionSettingsConditionTableInfo tableInfo{
+            .tableId = tableId,
+            .version = version,
     };
     return tableInfo;
 }
 
 static DemuxFilterSectionSettings getFilterSectionSettings(JNIEnv *env, const jobject& settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettings");
-    bool isCheckCrc = static_cast<bool>(
-            env->GetBooleanField(settings, env->GetFieldID(clazz, "mCrcEnabled", "Z")));
-    bool isRepeat = static_cast<bool>(
-            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRepeat", "Z")));
-    bool isRaw = static_cast<bool>(
-            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z")));
+    bool isCheckCrc = env->GetBooleanField(settings, env->GetFieldID(clazz, "mCrcEnabled", "Z"));
+    bool isRepeat = env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRepeat", "Z"));
+    bool isRaw = env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z"));
 
     DemuxFilterSectionSettings filterSectionSettings {
         .isCheckCrc = isCheckCrc,
@@ -3446,19 +3297,21 @@
     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;
 }
 
 static DemuxFilterAvSettings getFilterAvSettings(JNIEnv *env, const jobject& settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/filter/AvSettings");
-    bool isPassthrough = static_cast<bool>(
-            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsPassthrough", "Z")));
+    bool isPassthrough =
+            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsPassthrough", "Z"));
     DemuxFilterAvSettings filterAvSettings {
         .isPassthrough = isPassthrough,
     };
@@ -3478,13 +3331,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;
@@ -3492,10 +3345,8 @@
 
 static DemuxFilterPesDataSettings getFilterPesDataSettings(JNIEnv *env, const jobject& settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/filter/PesSettings");
-    uint16_t streamId = static_cast<uint16_t>(
-            env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I")));
-    bool isRaw = static_cast<bool>(
-            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z")));
+    int32_t streamId = env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I"));
+    bool isRaw = env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z"));
     DemuxFilterPesDataSettings filterPesDataSettings {
         .streamId = streamId,
         .isRaw = isRaw,
@@ -3505,8 +3356,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>>(
-            env->GetIntField(settings, env->GetFieldID(clazz, "mTsIndexMask", "I")));
+    int32_t tsIndexMask = env->GetIntField(settings, env->GetFieldID(clazz, "mTsIndexMask", "I"));
     DemuxRecordScIndexType scIndexType = static_cast<DemuxRecordScIndexType>(
             env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexType", "I")));
     jint scIndexMask = env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexMask", "I"));
@@ -3516,18 +3366,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>(
-            env->GetIntField(settings, env->GetFieldID(clazz, "mDownloadId", "I")));
+    int32_t downloadId = env->GetIntField(settings, env->GetFieldID(clazz, "mDownloadId", "I"));
 
     DemuxFilterDownloadSettings filterDownloadSettings {
         .downloadId = downloadId,
@@ -3555,23 +3403,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",
@@ -3579,13 +3427,8 @@
         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")));
-
-    res.srcPort = srcPort;
-    res.dstPort = dstPort;
+    res.srcPort = env->GetIntField(config, env->GetFieldID(clazz, "mSrcPort", "I"));
+    res.dstPort = env->GetIntField(config, env->GetFieldID(clazz, "mDstPort", "I"));
 
     return res;
 }
@@ -3604,74 +3447,84 @@
     switch (mainType) {
         case DemuxFilterMainType::TS: {
             jclass clazz = env->FindClass("android/media/tv/tuner/filter/TsFilterConfiguration");
-            uint16_t tpid = static_cast<uint16_t>(
-                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mTpid", "I")));
+            int32_t tpid = env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mTpid", "I"));
             DemuxTsFilterSettings tsFilterSettings {
                 .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: {
             jclass clazz = env->FindClass("android/media/tv/tuner/filter/MmtpFilterConfiguration");
-            uint16_t mmtpPid = static_cast<uint16_t>(
-                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mMmtpPid", "I")));
+            int32_t mmtpPid =
+                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mMmtpPid", "I"));
             DemuxMmtpFilterSettings mmtpFilterSettings {
                 .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: {
@@ -3681,28 +3534,29 @@
             };
 
             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(
                         "android/media/tv/tuner/filter/IpFilterConfiguration");
-                bool bPassthrough = static_cast<bool>(
-                        env->GetBooleanField(
-                                filterConfigObj, env->GetFieldID(
-                                        clazz, "mPassthrough", "Z")));
-                ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
+                bool bPassthrough =
+                        env->GetBooleanField(filterConfigObj,
+                                             env->GetFieldID(clazz, "mPassthrough", "Z"));
+                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>(
-                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I")));
-            bool isCompressedIpPacket = static_cast<bool>(
-                    env->GetBooleanField(
-                            filterConfigObj, env->GetFieldID(clazz, "mIsCompressedIpPacket", "Z")));
+            int32_t packetType =
+                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I"));
+            bool isCompressedIpPacket =
+                    env->GetBooleanField(filterConfigObj,
+                                         env->GetFieldID(clazz, "mIsCompressedIpPacket", "Z"));
 
             DemuxTlvFilterSettings tlvFilterSettings {
                 .packetType = packetType,
@@ -3710,23 +3564,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);
+                bool bPassthrough =
+                        env->GetBooleanField(filterConfigObj,
+                                             env->GetFieldID(clazz, "mPassthrough", "Z"));
+                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>(
-                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I")));
+            int32_t packetType =
+                    env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I"));
             DemuxAlpLengthType lengthType = static_cast<DemuxAlpLengthType>(
                     env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mLengthType", "I")));
             DemuxAlpFilterSettings alpFilterSettings {
@@ -3734,18 +3589,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: {
@@ -3766,34 +3622,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;
         }
     }
 
@@ -3801,99 +3656,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) ? 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;
@@ -3901,25 +3755,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);
+    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) {
@@ -3929,63 +3783,61 @@
 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(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");
     jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
 
-    jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+    jobject longObj = env->NewObject(longClazz, longInit, timestamp);
     return longObj;
 }
 
 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");
     jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
 
-    jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+    jobject longObj = env->NewObject(longClazz, longInit, timestamp);
     return longObj;
 }
 
 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;
     }
@@ -3995,7 +3847,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) {
@@ -4006,48 +3858,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]));
+    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(
@@ -4069,13 +3921,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 */) {
@@ -4090,106 +3942,102 @@
 
 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) {
     sp<LnbClient> lnbClient = getLnbClient(env, lnb);
     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;
+    env->GetByteArrayRegion(msg, 0, size, reinterpret_cast<jbyte *>(&v[0]));
+    return (jint)lnbClient->sendDiseqcMessage(v);
 }
 
 static int android_media_tv_Tuner_close_lnb(JNIEnv* env, jobject lnb) {
@@ -4199,34 +4047,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);
+    dvrClient->setFd(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;
     }
@@ -4237,42 +4085,41 @@
         ALOGD("Failed to GetByteArrayElements");
         return -1;
     }
-    long realSize = dvrClient->readFromBuffer(reinterpret_cast<signed char*>(src) + offset, size);
+    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;
     }
 
-    long realSize = dvrClient->writeToBuffer(reinterpret_cast<signed char*>(dst) + offset, size);
+    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) {
@@ -4282,9 +4129,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);
 
@@ -4294,23 +4141,23 @@
 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);
-    uint64_t audioHandle = mediaEventSp->getAudioHandle();
+    int64_t audioHandle = mediaEventSp->getAudioHandle();
     jclass longClazz = env->FindClass("java/lang/Long");
     jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
 
-    jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(audioHandle));
+    jobject longObj = env->NewObject(longClazz, longInit, audioHandle);
     return longObj;
 }
 
 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;
     }
@@ -4519,19 +4366,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 5d3b0a3..5401ddd 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,17 +103,17 @@
 };
 
 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, int64_t dataId,
+               int64_t dataSize, jobject obj);
     ~MediaEvent();
     jobject getLinearBlock();
-    uint64_t getAudioHandle();
+    int64_t getAudioHandle();
     void finalize();
 
     sp<FilterClient> mFilterClient;
     native_handle_t* mAvHandle;
-    uint64_t mDataId;
-    uint64_t mDataSize;
+    int64_t mDataId;
+    int64_t mDataSize;
     uint8_t* mBuffer;
     android::Mutex mLock;
     int mDataIdRefCnt;
@@ -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;
 };
@@ -182,10 +170,9 @@
     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);
@@ -214,18 +201,16 @@
     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 6c4295b..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,52 +16,41 @@
 
 #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;
 }
 
 Result DemuxClient::setFrontendDataSourceById(int frontendId) {
-    if (mTunerDemux != NULL) {
+    if (mTunerDemux != nullptr) {
         Status s = mTunerDemux->setFrontendDataSourceById(frontendId);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
@@ -69,251 +58,114 @@
     return Result::INVALID_STATE;
 }
 
-sp<FilterClient> DemuxClient::openFilter(DemuxFilterType type, int bufferSize,
-        sp<FilterClientCallback> cb) {
-    if (mTunerDemux != NULL) {
+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 46b0a3d..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,9 +45,6 @@
     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.
      */
@@ -68,7 +58,8 @@
     /**
      * 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.
@@ -78,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).
@@ -110,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..d4d8837 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) {
-        Status s = mTunerFilter->releaseAvHandle(makeToAidl(handle), avDataId);
+    if (mTunerFilter != nullptr) {
+        Status s = mTunerFilter->releaseAvHandle(dupToAidl(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 = dupFromAidl(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/OWNERS b/media/jni/tuner/OWNERS
new file mode 100644
index 0000000..bf9fe34
--- /dev/null
+++ b/media/jni/tuner/OWNERS
@@ -0,0 +1,2 @@
+hgchen@google.com
+quxiangfang@google.com
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/core/tests/uwbtests/Android.bp b/media/tests/aidltests/Android.bp
similarity index 85%
rename from core/tests/uwbtests/Android.bp
rename to media/tests/aidltests/Android.bp
index 31f446f..c3d5fa2 100644
--- a/core/tests/uwbtests/Android.bp
+++ b/media/tests/aidltests/Android.bp
@@ -1,4 +1,5 @@
-// Copyright 2020 The Android Open Source Project
+//
+// Copyright (C) 2021 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -11,6 +12,7 @@
 // WITHOUT 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 {
     // See: http://go/android-license-faq
@@ -22,17 +24,17 @@
 }
 
 android_test {
-    name: "UwbManagerTests",
+    name: "AidlConversionUnitTests",
+    srcs: ["src/**/*.java"],
     static_libs: [
-        "androidx.test.ext.junit",
         "androidx.test.rules",
-        "mockito-target-minus-junit4",
+        "platform-test-annotations",
     ],
     libs: [
-        "android.test.runner",
+        "framework",
     ],
-    srcs: ["src/**/*.java"],
+    sdk_version: "current",
     platform_apis: true,
-    certificate: "platform",
     test_suites: ["device-tests"],
+    certificate: "platform",
 }
diff --git a/core/tests/uwbtests/AndroidManifest.xml b/media/tests/aidltests/AndroidManifest.xml
similarity index 69%
rename from core/tests/uwbtests/AndroidManifest.xml
rename to media/tests/aidltests/AndroidManifest.xml
index dc991ff..ffa895a 100644
--- a/core/tests/uwbtests/AndroidManifest.xml
+++ b/media/tests/aidltests/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2020 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,17 +15,14 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.uwb">
+        package="android.media.audio.common">
 
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <!-- This is a self-instrumenting test package. -->
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.uwb"
-                     android:label="UWB Manager Tests">
-    </instrumentation>
-
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.media.audio.common"
+        android:label="Unit tests for AIDL conversion utilities" />
 </manifest>
-
diff --git a/media/tests/aidltests/AndroidTest.xml b/media/tests/aidltests/AndroidTest.xml
new file mode 100644
index 0000000..fb27a3c
--- /dev/null
+++ b/media/tests/aidltests/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="Runs AIDL Unit Tests">
+    <!--Test app needs to be installed when we change its settings below-->
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="AidlConversionUnitTests.apk"/>
+        <option name="cleanup-apks" value="true"/>
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="AidlConversionUnitTests"/>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.media.audio.common"/>
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+    </test>
+</configuration>
diff --git a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
new file mode 100644
index 0000000..5f64d20
--- /dev/null
+++ b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
@@ -0,0 +1,399 @@
+/*
+ * 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.media.audio.common;
+
+import android.media.AudioAttributes;
+import android.media.AudioFormat;
+import android.media.AudioSystem;
+import android.media.AudioTrack;
+import android.media.MediaFormat;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit tests for AidlConversion utilities.
+ *
+ * Run with "atest AidlConversionUnitTests".
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public final class AidlConversionUnitTests {
+
+    private static final String TAG = "AidlConvTests";
+    // Negative values are considered to be "invalid" as a general rule.
+    // However, '-1' is sometimes used as "system invalid" value, and thus
+    // does not cause an exception to be thrown during conversion.
+    private static int sInvalidValue = -2;
+    private static byte sInvalidValueByte = -2;
+
+    @Test
+    public void testAudioChannelConversionApiDefault() {
+        final AudioChannelLayout aidl = new AudioChannelLayout();
+        final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, false /*isInput*/);
+        assertEquals(AudioFormat.CHANNEL_OUT_DEFAULT, api);
+        final int apiInput = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, true /*isInput*/);
+        assertEquals(AudioFormat.CHANNEL_IN_DEFAULT, apiInput);
+    }
+
+    @Test
+    public void testAudioChannelConversionApiOutput() {
+        final AudioChannelLayout aidl = AudioChannelLayout.layoutMask(
+                AudioChannelLayout.LAYOUT_MONO);
+        final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, false /*isInput*/);
+        assertEquals(AudioFormat.CHANNEL_OUT_MONO, api);
+    }
+
+    @Test
+    public void testAudioChannelConversionApiInput() {
+        final AudioChannelLayout aidl = AudioChannelLayout.layoutMask(
+                AudioChannelLayout.LAYOUT_MONO);
+        final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, true /*isInput*/);
+        assertEquals(AudioFormat.CHANNEL_IN_MONO, api);
+    }
+
+    @Test
+    public void testAudioChannelConversionApiIndex() {
+        final AudioChannelLayout aidl = AudioChannelLayout.indexMask(
+                AudioChannelLayout.INDEX_MASK_1);
+        final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, false /*isInput*/);
+        assertEquals(1, api);
+        final int apiInput = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, true /*isInput*/);
+        assertEquals(1, apiInput);
+    }
+
+    @Test
+    public void testAudioChannelConversionApiVoice() {
+        final AudioChannelLayout aidl = AudioChannelLayout.voiceMask(
+                AudioChannelLayout.VOICE_UPLINK_MONO);
+        final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask(
+                aidl, true /*isInput*/);
+        assertEquals(AudioFormat.CHANNEL_IN_VOICE_UPLINK | AudioFormat.CHANNEL_IN_MONO, api);
+    }
+
+    @Test
+    public void testAudioConfigConversionApiIndex() {
+        final AudioConfig aidl = new AudioConfig();
+        aidl.base = new AudioConfigBase();
+        aidl.base.sampleRate = 8000;
+        aidl.base.channelMask = AudioChannelLayout.indexMask(AudioChannelLayout.INDEX_MASK_1);
+        aidl.base.format = createPcm16FormatAidl();
+        // Other fields in AudioConfig are irrelevant.
+        final AudioFormat api = AidlConversion.aidl2api_AudioConfig_AudioFormat(
+                aidl, false /*isInput*/);
+        final AudioFormat apiInput = AidlConversion.aidl2api_AudioConfig_AudioFormat(
+                aidl, true /*isInput*/);
+        assertEquals(api, apiInput);
+        assertEquals(8000, api.getSampleRate());
+        assertEquals(1, api.getChannelIndexMask());
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, api.getEncoding());
+    }
+
+    @Test
+    public void testAudioConfigConversionApiLayout() {
+        final AudioConfig aidl = new AudioConfig();
+        aidl.base = new AudioConfigBase();
+        aidl.base.sampleRate = 8000;
+        aidl.base.channelMask = AudioChannelLayout.layoutMask(AudioChannelLayout.LAYOUT_MONO);
+        aidl.base.format = createPcm16FormatAidl();
+        // Other fields in AudioConfig are irrelevant.
+        final AudioFormat api = AidlConversion.aidl2api_AudioConfig_AudioFormat(
+                aidl, false /*isInput*/);
+        assertEquals(8000, api.getSampleRate());
+        assertEquals(AudioFormat.CHANNEL_OUT_MONO, api.getChannelMask());
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, api.getEncoding());
+        final AudioFormat apiInput = AidlConversion.aidl2api_AudioConfig_AudioFormat(
+                aidl, true /*isInput*/);
+        assertEquals(8000, apiInput.getSampleRate());
+        assertEquals(AudioFormat.CHANNEL_IN_MONO, apiInput.getChannelMask());
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, apiInput.getEncoding());
+    }
+
+    @Test
+    public void testAudioConfigBaseConversionApiIndex() {
+        final AudioConfigBase aidl = new AudioConfigBase();
+        aidl.sampleRate = 8000;
+        aidl.channelMask = AudioChannelLayout.indexMask(AudioChannelLayout.INDEX_MASK_1);
+        aidl.format = createPcm16FormatAidl();
+        final AudioFormat api = AidlConversion.aidl2api_AudioConfigBase_AudioFormat(
+                aidl, false /*isInput*/);
+        final AudioFormat apiInput = AidlConversion.aidl2api_AudioConfigBase_AudioFormat(
+                aidl, true /*isInput*/);
+        assertEquals(api, apiInput);
+        assertEquals(8000, api.getSampleRate());
+        assertEquals(1, api.getChannelIndexMask());
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, api.getEncoding());
+    }
+
+    @Test
+    public void testAudioConfigBaseConversionApiLayout() {
+        final AudioConfigBase aidl = new AudioConfigBase();
+        aidl.sampleRate = 8000;
+        aidl.channelMask = AudioChannelLayout.layoutMask(AudioChannelLayout.LAYOUT_MONO);
+        aidl.format = createPcm16FormatAidl();
+        final AudioFormat api = AidlConversion.aidl2api_AudioConfigBase_AudioFormat(
+                aidl, false /*isInput*/);
+        assertEquals(8000, api.getSampleRate());
+        assertEquals(AudioFormat.CHANNEL_OUT_MONO, api.getChannelMask());
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, api.getEncoding());
+        final AudioFormat apiInput = AidlConversion.aidl2api_AudioConfigBase_AudioFormat(
+                aidl, true /*isInput*/);
+        assertEquals(8000, apiInput.getSampleRate());
+        assertEquals(AudioFormat.CHANNEL_IN_MONO, apiInput.getChannelMask());
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, apiInput.getEncoding());
+    }
+
+    @Test
+    public void testAudioFormatConversionApiDefault() {
+        final AudioFormatDescription aidl = new AudioFormatDescription();
+        final int api = AidlConversion.aidl2api_AudioFormat_AudioFormatEncoding(aidl);
+        assertEquals(AudioFormat.ENCODING_DEFAULT, api);
+    }
+
+    @Test
+    public void testAudioFormatConversionApiPcm16() {
+        final AudioFormatDescription aidl = createPcm16FormatAidl();
+        final int api = AidlConversion.aidl2api_AudioFormat_AudioFormatEncoding(aidl);
+        assertEquals(AudioFormat.ENCODING_PCM_16BIT, api);
+    }
+
+    @Test
+    public void testAudioFormatConversionApiAacLc() {
+        final AudioFormatDescription aidl = new AudioFormatDescription();
+        aidl.type = AudioFormatType.NON_PCM;
+        aidl.encoding = MediaFormat.MIMETYPE_AUDIO_AAC_LC;
+        final int api = AidlConversion.aidl2api_AudioFormat_AudioFormatEncoding(aidl);
+        assertEquals(AudioFormat.ENCODING_AAC_LC, api);
+    }
+
+    @Test
+    public void testAudioChannelConversionLegacyDefault() {
+        final int legacy = 0; /*AUDIO_CHANNEL_NONE*/
+        final AudioChannelLayout aidl =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, false /*isInput*/);
+        final AudioChannelLayout aidlInput =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, true /*isInput*/);
+        assertEquals(aidl, aidlInput);
+        assertEquals(AudioChannelLayout.none, aidl.getTag());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, false /*isInput*/);
+        final int legacyBackInput =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, true /*isInput*/);
+        assertEquals(legacy, legacyBack);
+        assertEquals(legacy, legacyBackInput);
+    }
+
+    @Test
+    public void testAudioChannelConversionLegacyOutput() {
+        final int legacy = 1; /*AUDIO_CHANNEL_OUT_MONO*/
+        final AudioChannelLayout aidl =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, false /*isInput*/);
+        assertEquals(AudioChannelLayout.layoutMask, aidl.getTag());
+        assertEquals(AudioChannelLayout.LAYOUT_MONO, aidl.getLayoutMask());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, false /*isInput*/);
+        assertEquals(legacy, legacyBack);
+    }
+
+    @Test
+    public void testAudioChannelConversionLegacyInput() {
+        final int legacy = 0x10; /*AUDIO_CHANNEL_IN_MONO*/
+        final AudioChannelLayout aidl =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, true /*isInput*/);
+        assertEquals(AudioChannelLayout.layoutMask, aidl.getTag());
+        assertEquals(AudioChannelLayout.LAYOUT_MONO, aidl.getLayoutMask());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, true /*isInput*/);
+        assertEquals(legacy, legacyBack);
+    }
+
+    @Test
+    public void testAudioChannelConversionLegacyIndex() {
+        final int legacy = 0x80000001; /*AUDIO_CHANNEL_INDEX_MASK_1*/
+        final AudioChannelLayout aidl =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, false /*isInput*/);
+        final AudioChannelLayout aidlInput =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, true /*isInput*/);
+        assertEquals(aidl, aidlInput);
+        assertEquals(AudioChannelLayout.indexMask, aidl.getTag());
+        assertEquals(AudioChannelLayout.INDEX_MASK_1, aidl.getIndexMask());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, false /*isInput*/);
+        final int legacyBackInput =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, true /*isInput*/);
+        assertEquals(legacy, legacyBack);
+        assertEquals(legacy, legacyBackInput);
+    }
+
+    @Test
+    public void testAudioChannelConversionLegacyVoice() {
+        final int legacy = 0x4010; /*AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO*/
+        final AudioChannelLayout aidl =
+                AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        legacy, true /*isInput*/);
+        assertEquals(AudioChannelLayout.voiceMask, aidl.getTag());
+        assertEquals(AudioChannelLayout.VOICE_UPLINK_MONO, aidl.getVoiceMask());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        aidl, true /*isInput*/);
+        assertEquals(legacy, legacyBack);
+    }
+
+    @Test
+    public void testAudioChannelConversionLegacyInvalid() {
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        AudioChannelLayout.voiceMask(sInvalidValue), false /*isInput*/));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+                        AudioChannelLayout.voiceMask(sInvalidValue), true /*isInput*/));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        sInvalidValue, false /*isInput*/));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                        sInvalidValue, true /*isInput*/));
+    }
+
+    @Test
+    public void testAudioFormatConversionLegacyDefault() {
+        final int legacy = AudioSystem.AUDIO_FORMAT_DEFAULT;
+        final AudioFormatDescription aidl =
+                AidlConversion.legacy2aidl_audio_format_t_AudioFormatDescription(legacy);
+        assertEquals(AudioFormatType.DEFAULT, aidl.type);
+        assertNotNull(aidl.encoding);
+        assertTrue(aidl.encoding.isEmpty());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioFormatDescription_audio_format_t(aidl);
+        assertEquals(legacy, legacyBack);
+    }
+
+    @Test
+    public void testAudioFormatConversionLegacyPcm16() {
+        final int legacy = 1; /*AUDIO_FORMAT_PCM_16_BIT*/
+        final AudioFormatDescription aidl =
+                AidlConversion.legacy2aidl_audio_format_t_AudioFormatDescription(legacy);
+        assertEquals(AudioFormatType.PCM, aidl.type);
+        assertEquals(PcmType.INT_16_BIT, aidl.pcm);
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioFormatDescription_audio_format_t(aidl);
+        assertEquals(legacy, legacyBack);
+    }
+
+    @Test
+    public void testAudioFormatConversionLegacyAac() {
+        final int legacy = AudioSystem.AUDIO_FORMAT_AAC;
+        final AudioFormatDescription aidl =
+                AidlConversion.legacy2aidl_audio_format_t_AudioFormatDescription(legacy);
+        assertEquals(AudioFormatType.NON_PCM, aidl.type);
+        assertNotNull(aidl.encoding);
+        assertFalse(aidl.encoding.isEmpty());
+        final int legacyBack =
+                AidlConversion.aidl2legacy_AudioFormatDescription_audio_format_t(aidl);
+        assertEquals(legacy, legacyBack);
+    }
+
+    @Test
+    public void testAudioFormatConversionLegacyInvalid() {
+        final AudioFormatDescription aidl = new AudioFormatDescription();
+        aidl.type = sInvalidValueByte;
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.aidl2legacy_AudioFormatDescription_audio_format_t(aidl));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.legacy2aidl_audio_format_t_AudioFormatDescription(
+                        sInvalidValue));
+    }
+
+    @Test
+    public void testAudioEncapsulationModeConversionLegacy() {
+        // AIDL values are synchronized with SDK, so we can use the SDK values as AIDL.
+        final int aidl = AudioTrack.ENCAPSULATION_MODE_ELEMENTARY_STREAM;
+        final int legacy =
+                AidlConversion.aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(aidl);
+        final int aidlBack =
+                AidlConversion.legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(
+                        legacy);
+        assertEquals(aidl, aidlBack);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(
+                        sInvalidValue));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(
+                        sInvalidValue));
+    }
+
+    @Test
+    public void testAudioStreamTypeConversionLegacy() {
+        // AIDL values are synchronized with SDK, so we can use the SDK values as AIDL.
+        final int aidl = AudioSystem.STREAM_MUSIC;
+        final int legacy = AidlConversion.aidl2legacy_AudioStreamType_audio_stream_type_t(aidl);
+        final int aidlBack = AidlConversion.legacy2aidl_audio_stream_type_t_AudioStreamType(legacy);
+        assertEquals(aidl, aidlBack);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.aidl2legacy_AudioStreamType_audio_stream_type_t(
+                        sInvalidValue));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.legacy2aidl_audio_stream_type_t_AudioStreamType(
+                        sInvalidValue));
+    }
+
+    @Test
+    public void testAudioUsageConversionLegacy() {
+        // AIDL values are synchronized with SDK, so we can use the SDK values as AIDL.
+        final int aidl = AudioAttributes.USAGE_MEDIA;
+        final int legacy = AidlConversion.aidl2legacy_AudioUsage_audio_usage_t(aidl);
+        final int aidlBack = AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(legacy);
+        assertEquals(aidl, aidlBack);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.aidl2legacy_AudioUsage_audio_usage_t(sInvalidValue));
+        assertThrows(IllegalArgumentException.class,
+                () -> AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(sInvalidValue));
+    }
+
+    private static AudioFormatDescription createPcm16FormatAidl() {
+        final AudioFormatDescription aidl = new AudioFormatDescription();
+        aidl.type = AudioFormatType.PCM;
+        aidl.pcm = PcmType.INT_16_BIT;
+        return aidl;
+    }
+}
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/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/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index c1a0a9a..b4cafd8 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -93,9 +93,9 @@
             final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0);
             setTitle(Html.fromHtml(getString(
                     R.string.confirmation_title,
-                    getCallingAppName(),
-                    profileName,
-                    selectedDevice.getDisplayName()), 0));
+                    Html.escapeHtml(getCallingAppName()),
+                    Html.escapeHtml(selectedDevice.getDisplayName())), 0));
+
             mPairButton = findViewById(R.id.button_pair);
             mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
             getService().mSelectedDevice = selectedDevice;
@@ -108,8 +108,8 @@
             mPairButton = findViewById(R.id.button_pair);
             mPairButton.setVisibility(View.GONE);
             setTitle(Html.fromHtml(getString(R.string.chooser_title,
-                    profileName,
-                    getCallingAppName()), 0));
+                    Html.escapeHtml(profileName),
+                    Html.escapeHtml(getCallingAppName())), 0));
             mDeviceListView = findViewById(R.id.device_list);
             mDevicesAdapter = new DevicesAdapter();
             mDeviceListView.setAdapter(mDevicesAdapter);
diff --git a/packages/DynamicSystemInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml
index b4d520d..1bc4983 100644
--- a/packages/DynamicSystemInstallationService/AndroidManifest.xml
+++ b/packages/DynamicSystemInstallationService/AndroidManifest.xml
@@ -33,6 +33,10 @@
             <intent-filter>
                 <action android:name="android.os.image.action.START_INSTALL" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="content" />
+                <data android:scheme="file" />
+                <data android:scheme="http" />
+                <data android:scheme="https" />
             </intent-filter>
         </activity>
 
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 8951e0d..806734f 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -45,14 +45,14 @@
     <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ఖాళీ లేదు"</string>
     <string name="out_of_space_dlg_text" msgid="8727714096031856231">"<xliff:g id="APP_NAME">%1$s</xliff:g>ని ఇన్‌స్టాల్ చేయడం సాధ్యపడలేదు. కొంత స్థలాన్ని ఖాళీ చేసి మళ్లీ ప్రయత్నించండి."</string>
     <string name="app_not_found_dlg_title" msgid="5107924008597470285">"యాప్ కనుగొనబడలేదు"</string>
-    <string name="app_not_found_dlg_text" msgid="5219983779377811611">"ఇన్‌స్టాల్ చేసిన యాప్‌ల జాబితాలో యాప్ కనుగొనబడలేదు."</string>
+    <string name="app_not_found_dlg_text" msgid="5219983779377811611">"ఇన్‌స్టాల్ చేసిన యాప్‌ల లిస్ట్‌లో యాప్ కనుగొనబడలేదు."</string>
     <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"అనుమతించబడలేదు"</string>
     <string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"ప్రస్తుత వినియోగదారు ఈ అన్ఇన్‌స్టాలేషన్ చేసేందుకు అనుమతించబడరు."</string>
     <string name="generic_error_dlg_title" msgid="5863195085927067752">"లోపం"</string>
     <string name="generic_error_dlg_text" msgid="5287861443265795232">"యాప్‌ను అన్ఇన్‌స్టాల్ చేయడం సాధ్యపడలేదు."</string>
     <string name="uninstall_application_title" msgid="4045420072401428123">"యాప్‌ను అన్‌ఇన్‌స్టాల్ చేయి"</string>
     <string name="uninstall_update_title" msgid="824411791011583031">"అప్‌డేట్ అన్‌ఇన్‌స్టాల్ చేయి"</string>
-    <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> అనేది క్రింది యాప్‌లో ఒక భాగం:"</string>
+    <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> అనేది కింది యాప్‌లో ఒక భాగం:"</string>
     <string name="uninstall_application_text" msgid="3816830743706143980">"మీరు ఈ యాప్‌ను అన్‌ఇన్‌స్టాల్ చేయాలనుకుంటున్నారా?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"మీరు ఈ యాప్‌ను "<b>"అందరు"</b>" వినియోగదారులకు అన్‌ఇన్‌స్టాల్ చేయాలనుకుంటున్నారా? అప్లికేషన్, దాని డేటా పరికరంలోని "<b>"అందరు"</b>" వినియోగదారుల నుండి తీసివేయబడుతుంది."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"మీరు వినియోగదారు <xliff:g id="USERNAME">%1$s</xliff:g> కోసం ఈ యాప్‌ను అన్‌ఇన్‌స్టాల్ చేయాలనుకుంటున్నారా?"</string>
@@ -83,10 +83,10 @@
     <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>
+    <string name="anonymous_source_continue" msgid="4375745439457209366">"కొనసాగండి"</string>
     <string name="external_sources_settings" msgid="4046964413071713807">"సెట్టింగ్‌లు"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"Wear యాప్‌లను ఇన్‌స్టాల్/అన్‌ఇన్‌స్టాల్ చేస్తోంది"</string>
     <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"యాప్ ఇన్‌స్టాల్ చేయబడిందనే నోటిఫికేషన్"</string>
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
index 5f107d6..34e7e3d 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -84,8 +84,7 @@
      */
     public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
             @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
-        mName = context.getResources().getIdentifier(name, null,
-                "com.android.printservice.recommendation");
+        mName = context.getResources().getIdentifier(name, null, context.getPackageName());
         mPackageName = packageName;
         mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPES,
                 new VendorNameFilter(new HashSet<>(mDNSNames)));
diff --git a/packages/PrintSpooler/res/values-as/strings.xml b/packages/PrintSpooler/res/values-as/strings.xml
index b6b287f..a93fceb 100644
--- a/packages/PrintSpooler/res/values-as/strings.xml
+++ b/packages/PrintSpooler/res/values-as/strings.xml
@@ -47,7 +47,7 @@
     <string name="savetopdf_button" msgid="2976186791686924743">"PDFৰ জৰিয়তে ছেভ কৰক"</string>
     <string name="print_options_expanded" msgid="6944679157471691859">"প্ৰিণ্ট বিকল্পসমূহ বিস্তাৰ কৰা হ’ল"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"প্ৰিণ্ট বিকল্পসমূহ সংকুচিত কৰা হ’ল"</string>
-    <string name="search" msgid="5421724265322228497">"Search"</string>
+    <string name="search" msgid="5421724265322228497">"সন্ধান কৰক"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"সকলো প্ৰিণ্টাৰ"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"সেৱা যোগ কৰক"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"সন্ধান বাকচটো দেখুওৱা হ’ল"</string>
diff --git a/packages/PrintSpooler/res/values-kn/strings.xml b/packages/PrintSpooler/res/values-kn/strings.xml
index 261fe4b..150ede4 100644
--- a/packages/PrintSpooler/res/values-kn/strings.xml
+++ b/packages/PrintSpooler/res/values-kn/strings.xml
@@ -47,7 +47,7 @@
     <string name="savetopdf_button" msgid="2976186791686924743">"PDF ಗೆ ಉಳಿಸು"</string>
     <string name="print_options_expanded" msgid="6944679157471691859">"ಪ್ರಿಂಟ್ ಆಯ್ಕೆಗಳನ್ನು ವಿಸ್ತರಿಸಲಾಗಿದೆ"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"ಪ್ರಿಂಟ್ ಆಯ್ಕೆಗಳನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
-    <string name="search" msgid="5421724265322228497">"Search"</string>
+    <string name="search" msgid="5421724265322228497">"ಹುಡುಕಿ"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"ಎಲ್ಲಾ ಪ್ರಿಂಟರ್‌ಗಳು"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"ಸೇವೆಯನ್ನು ಸೇರಿಸು"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ಹುಡುಕಾಟ ಪೆಟ್ಟಿಗೆಯನ್ನು ತೋರಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/PrintSpooler/res/values-ml/strings.xml b/packages/PrintSpooler/res/values-ml/strings.xml
index 73af95d..dbcd34b 100644
--- a/packages/PrintSpooler/res/values-ml/strings.xml
+++ b/packages/PrintSpooler/res/values-ml/strings.xml
@@ -47,7 +47,7 @@
     <string name="savetopdf_button" msgid="2976186791686924743">"PDF-ൽ സംരക്ഷിക്കുക"</string>
     <string name="print_options_expanded" msgid="6944679157471691859">"പ്രിന്റ് ചെയ്യാനുള്ള ഓപ്‌ഷനുകൾ വിപുലീകരിച്ചു"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"പ്രിന്റ് ചെയ്യാനുള്ള ഓപ്‌ഷനുകൾ ചുരുക്കി"</string>
-    <string name="search" msgid="5421724265322228497">"Search"</string>
+    <string name="search" msgid="5421724265322228497">"തിരയൽ"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"എല്ലാ പ്രിന്ററുകളും"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"സേവനം ചേർക്കുക"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"തിരയൽ ബോക്‌സ് ദൃശ്യമാക്കിയിരിക്കുന്നു"</string>
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index 8119439..e1fa390 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -47,7 +47,7 @@
     <string name="savetopdf_button" msgid="2976186791686924743">"पीडीएफ वर सेव्ह करा"</string>
     <string name="print_options_expanded" msgid="6944679157471691859">"प्रिंट पर्याय विस्तृत झाले"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"प्रिंट पर्याय संक्षिप्त झाले"</string>
-    <string name="search" msgid="5421724265322228497">"Search"</string>
+    <string name="search" msgid="5421724265322228497">"शोधा"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"सर्व प्रिंटर"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"सेवा जोडा"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"शोध बॉक्स दर्शविला"</string>
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index d6f920f..fa10909 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -47,7 +47,7 @@
     <string name="savetopdf_button" msgid="2976186791686924743">"PDFରେ ସେଭ୍‍ କରନ୍ତୁ"</string>
     <string name="print_options_expanded" msgid="6944679157471691859">"ପ୍ରିଣ୍ଟ ବିକଳ୍ପକୁ ବଡ଼ କରାଯାଇଛି"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"ପ୍ରିଣ୍ଟ ବିକଳ୍ପକୁ ଛୋଟ କରାଯାଇଛି"</string>
-    <string name="search" msgid="5421724265322228497">"Search"</string>
+    <string name="search" msgid="5421724265322228497">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"ସମସ୍ତ ପ୍ରିଣ୍ଟର୍‌"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"ସେବା ଯୋଗ କରନ୍ତୁ"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ସର୍ଚ୍ଚ ବକ୍ସ ଦେଖାଯାଇଛି"</string>
diff --git a/packages/PrintSpooler/res/values-ta/strings.xml b/packages/PrintSpooler/res/values-ta/strings.xml
index eaf05b1..7ffac67 100644
--- a/packages/PrintSpooler/res/values-ta/strings.xml
+++ b/packages/PrintSpooler/res/values-ta/strings.xml
@@ -63,7 +63,7 @@
     <string name="printer_info_desc" msgid="7181988788991581654">"இந்தப் பிரிண்டர் பற்றிய கூடுதல் தகவல்"</string>
     <string name="notification_channel_progress" msgid="872788690775721436">"இயக்கத்திலுள்ள அச்சுப் பணிகள்"</string>
     <string name="notification_channel_failure" msgid="9042250774797916414">"தோல்வியடைந்த அச்சுப் பணிகள்"</string>
-    <string name="could_not_create_file" msgid="3425025039427448443">"கோப்பை உருவாக்க முடியவில்லை"</string>
+    <string name="could_not_create_file" msgid="3425025039427448443">"ஃபைலை உருவாக்க முடியவில்லை"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"சில அச்சுப் பொறிகள் முடக்கப்பட்டன"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"பிரிண்டர்களைத் தேடுகிறது"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
index e74ac44..fede44f 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
@@ -33,18 +33,18 @@
     <style name="Banner.Title.SettingsLib"
         parent="@android:style/TextAppearance.Material.Subhead">
         <item name="android:textSize">20sp</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
     <style name="Banner.Subtitle.SettingsLib"
-        parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+        parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textSize">14sp</item>
     </style>
 
     <style name="Banner.Summary.SettingsLib"
-        parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+        parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textSize">14sp</item>
     </style>
@@ -58,4 +58,4 @@
         parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
         <item name="android:textColor">?android:attr/colorAccent</item>
     </style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
index df47c64..4c6ed58 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
@@ -17,14 +17,13 @@
 
 <resources>
     <style name="Banner.Text.Title"
-           parent="@android:style/TextAppearance.Material.Subhead">
+           parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
         <item name="android:textSize">16sp</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
     <style name="Banner.Text.Summary"
-           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+           parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textSize">14sp</item>
     </style>
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 92514ad..1c44207 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -87,9 +87,9 @@
     </style>
 
     <style name="BarChart.Text"
-           parent="@android:style/TextAppearance.Material.Subhead">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+           parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">16sp</item>
     </style>
 
     <style name="BarChart.Text.HeaderTitle">
@@ -101,7 +101,7 @@
     </style>
 
     <style name="BarChart.Text.Summary"
-           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+           parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textSize">12sp</item>
     </style>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 2f911c4..238e65e 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -19,6 +19,7 @@
         "com.google.android.material_material",
         "SettingsLibSettingsTransition",
         "SettingsLibUtils",
+        "SettingsLibSettingsTheme",
     ],
     sdk_version: "system_current",
     min_sdk_version: "29",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
index 5950656..907863e 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
@@ -16,7 +16,6 @@
   -->
 <androidx.coordinatorlayout.widget.CoordinatorLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/content_parent"
     android:layout_width="match_parent"
@@ -40,7 +39,7 @@
             android:clipToPadding="false"
             app:forceApplySystemWindowInsetTop="true"
             app:extraMultilineHeightEnabled="true"
-            app:contentScrim="?androidprv:attr/colorSurfaceHeader"
+            app:contentScrim="@color/settingslib_colorSurfaceHeader"
             app:maxLines="3"
             app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
             app:scrimAnimationDuration="50"
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
similarity index 83%
rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
index 878275a0..c20beaf 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
@@ -18,7 +18,7 @@
     <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
         <item name="elevationOverlayEnabled">true</item>
         <item name="elevationOverlayColor">?attr/colorPrimary</item>
-        <item name="colorPrimary">@*android:color/primary_dark_device_default_settings</item>
-        <item name="colorAccent">@*android:color/accent_device_default_dark</item>
+        <item name="colorPrimary">@color/settingslib_primary_dark_device_default_settings</item>
+        <item name="colorAccent">@color/settingslib_accent_device_default_dark</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml
similarity index 100%
rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml
rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
similarity index 77%
rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
index 63d397c..d0b6c4d 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
@@ -16,11 +16,13 @@
 -->
 <resources>
     <style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
         <item name="android:textSize">20dp</item>
+        <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
     </style>
 
     <style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
         <item name="android:textSize">36dp</item>
+        <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
similarity index 82%
copy from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
copy to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
index 878275a0..9ecc297 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
@@ -18,7 +18,7 @@
     <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
         <item name="elevationOverlayEnabled">true</item>
         <item name="elevationOverlayColor">?attr/colorPrimary</item>
-        <item name="colorPrimary">@*android:color/primary_dark_device_default_settings</item>
-        <item name="colorAccent">@*android:color/accent_device_default_dark</item>
+        <item name="colorPrimary">@color/settingslib_primary_device_default_settings_light</item>
+        <item name="colorAccent">@color/settingslib_accent_device_default_light</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml
deleted file mode 100644
index 2e7a6a9..0000000
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>
-    <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
-        <item name="elevationOverlayEnabled">true</item>
-        <item name="elevationOverlayColor">?attr/colorPrimary</item>
-        <item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
-        <item name="colorAccent">@*android:color/accent_device_default_light</item>
-    </style>
-</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/res/values/styles.xml b/packages/SettingsLib/FooterPreference/res/values/styles.xml
index 08dd359..5a3bada 100644
--- a/packages/SettingsLib/FooterPreference/res/values/styles.xml
+++ b/packages/SettingsLib/FooterPreference/res/values/styles.xml
@@ -17,9 +17,8 @@
 
 <resources>
     <style name="TextAppearance.Footer.Title.SettingsLib"
-           parent="@android:style/TextAppearance.DeviceDefault.Medium">
+           parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
         <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textColor">?android:attr/colorAccent</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
index 4a99e84..2ffe6d9 100644
--- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml
+++ b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
@@ -24,14 +24,13 @@
     </style>
 
     <style name="TextAppearance.EntityHeaderTitle"
-           parent="@android:style/TextAppearance.Material.Subhead">
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+           parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">20sp</item>
     </style>
 
     <style name="TextAppearance.EntityHeaderSummary"
-           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+           parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textAlignment">viewStart</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:singleLine">true</item>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml
similarity index 100%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml
similarity index 100%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml
similarity index 100%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 6e5911c..30748e6 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -50,7 +50,7 @@
             android:tint="?android:attr/colorAccent"
             android:layout_gravity="center_vertical"
             android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
-            android:src="@*android:drawable/ic_info"
+            android:src="@android:drawable/ic_info"
             android:visibility="gone" />
 
         <Switch
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index 306145a..d0c2d0b 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -28,7 +28,7 @@
         android:layout_gravity="center_vertical"
         android:maxLines="2"
         android:ellipsize="end"
-        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
+        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
         android:textSize="16sp"
         android:textColor="?android:attr/textColorPrimaryInverse"
         android:layout_marginStart="@dimen/settingslib_switchbar_subsettings_margin_start"
@@ -42,7 +42,7 @@
         android:theme="@android:style/Theme.Material"
         android:layout_gravity="center_vertical"
         android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
-        android:src="@*android:drawable/ic_info"
+        android:src="@android:drawable/ic_info"
         android:visibility="gone"/>
 
     <Switch
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
new file mode 100644
index 0000000..2272a37
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
@@ -0,0 +1,37 @@
+<?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>
+
+    <!-- Size of layout margin -->
+    <dimen name="settingslib_switchbar_margin">16dp</dimen>
+
+    <!-- Size of layout margin left -->
+    <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
+
+    <!-- Size of layout margin right -->
+    <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
+
+    <!-- Minimum width of switch -->
+    <dimen name="settingslib_min_switch_width">52dp</dimen>
+
+    <!-- Minimum width of switch bar -->
+    <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
+
+    <!-- Radius of switch bar -->
+    <dimen name="settingslib_switch_bar_radius">28dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
new file mode 100644
index 0000000..a50fc7c
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.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.
+  -->
+
+<resources>
+
+    <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+        <item name="android:textSize">20sp</item>
+        <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
+        <item name="android:textColor">@android:color/black</item>
+    </style>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 16b8af6..6362882 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2020 The Android Open Source Project
+  Copyright (C) 2021 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -17,30 +17,12 @@
 
 <resources>
 
-    <!-- Size of layout margin -->
-    <dimen name="settingslib_switchbar_margin">16dp</dimen>
-
-    <!-- Size of layout margin left -->
-    <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
-
-    <!-- Size of layout margin right -->
-    <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
-
-    <!-- Minimum width of switch -->
-    <dimen name="settingslib_min_switch_width">52dp</dimen>
-
-    <!-- Minimum width of switch bar -->
-    <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
-
     <!-- Restricted icon size in switch bar -->
-    <dimen name="settingslib_restricted_icon_size">@*android:dimen/config_restrictedIconSize</dimen>
+    <dimen name="settingslib_restricted_icon_size">@android:dimen/config_restrictedIconSize</dimen>
 
     <!-- Restricted icon in switch bar -->
     <dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
 
-    <!-- Radius of switch bar -->
-    <dimen name="settingslib_switch_bar_radius">28dp</dimen>
-
     <!-- Size of title margin -->
     <dimen name="settingslib_switch_title_margin">16dp</dimen>
 
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
index 3924e30..870812a 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-   Copyright (C) 2020 The Android Open Source Project
+   Copyright (C) 2021 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -17,13 +17,6 @@
 
 <resources>
 
-    <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
-        <item name="android:textSize">20sp</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@android:color/black</item>
-    </style>
-
-
     <style name="SwitchBar.Switch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
         <item name="android:trackTint">@color/settingslib_switchbar_switch_track_tint</item>
         <item name="android:thumbTint">@color/settingslib_switchbar_switch_thumb_tint</item>
diff --git a/packages/SettingsLib/SearchWidget/res/values-te/strings.xml b/packages/SettingsLib/SearchWidget/res/values-te/strings.xml
index c5ece74..dbad586 100644
--- a/packages/SettingsLib/SearchWidget/res/values-te/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-te/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1914043873178389845">"సెట్టింగ్‌లను వెతకండి"</string>
+    <string name="search_menu" msgid="1914043873178389845">"సెట్టింగ్‌లను సెర్చ్ చేయండి"</string>
 </resources>
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/SettingsTheme/res/color-v31/settingslib_surface_light.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
new file mode 100644
index 0000000..037b80a
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 8c7c7ed..c206903 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -36,4 +36,11 @@
     <color name="settingslib_dialog_colorError">#f28b82</color> <!-- Red 300 -->
 
     <color name="settingslib_colorSurfaceVariant">@android:color/system_neutral1_700</color>
+
+    <color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_700</color>
+
+    <!-- copy from accent_primary_variant_dark_device_default-->
+    <color name="settingslib_accent_primary_variant">@android:color/system_accent1_300</color>
+
+    <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_50</color>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index 77f1bcd..0401098 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -37,9 +37,32 @@
     <!-- Dialog accent color -->
     <color name="settingslib_dialog_accent">@android:color/system_accent1_600</color>
     <!-- Dialog background color -->
-    <color name="settingslib_dialog_background">@*android:color/surface_light</color>
+    <color name="settingslib_dialog_background">@color/settingslib_surface_light</color>
     <!-- Dialog error color. -->
     <color name="settingslib_dialog_colorError">#d93025</color> <!-- Red 600 -->
 
     <color name="settingslib_colorSurfaceVariant">@android:color/system_neutral2_100</color>
+
+    <color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_100</color>
+
+    <color name="settingslib_accent_device_default_dark">@android:color/system_accent1_100</color>
+
+    <color name="settingslib_accent_device_default_light">@android:color/system_accent1_600</color>
+
+    <color name="settingslib_primary_dark_device_default_settings">@android:color/system_neutral1_900</color>
+
+    <color name="settingslib_primary_device_default_settings_light">@android:color/system_neutral1_50</color>
+
+    <color name="settingslib_accent_primary_device_default">@android:color/system_accent1_100</color>
+
+    <!-- copy from accent_primary_variant_light_device_default-->
+    <color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color>
+
+    <color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color>
+
+    <color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color>
+
+    <color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
+
+    <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
index ddcc83e..1c33f1a 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
@@ -19,4 +19,5 @@
     <dimen name="app_preference_padding_start">20dp</dimen>
     <dimen name="app_icon_min_width">52dp</dimen>
     <dimen name="settingslib_preferred_minimum_touch_target">48dp</dimen>
+    <dimen name="settingslib_dialogCornerRadius">28dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml
new file mode 100644
index 0000000..6d072a9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml
@@ -0,0 +1,37 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of a font family to use for headlines in SettingsLib. -->
+    <string name="settingslib_config_headlineFontFamily" translatable="false">
+        @*android:string/config_headlineFontFamily
+    </string>
+
+    <!-- Name of a font family to use for headlines-medium in SettingsLib. -->
+    <string name="settingslib_config_headlineFontFamilyMedium" translatable="false">
+        @*android:string/config_headlineFontFamilyMedium
+    </string>
+
+    <!-- Name of a font family to use for body in SettingsLib. -->
+    <string name="settingslib_config_bodyFontFamily" translatable="false">
+        @*android:string/config_bodyFontFamily
+    </string>
+
+    <!-- Name of a font family to use for body-medium in SettingsLib. -->
+    <string name="settingslib_config_bodyFontFamilyMedium" translatable="false">
+        @*android:string/config_bodyFontFamilyMedium
+    </string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 46f1e03..5800636 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -16,12 +16,16 @@
   -->
 <resources>
     <style name="TextAppearance.PreferenceTitle.SettingsLib"
-           parent="@*android:style/TextAppearance.DeviceDefault.ListItem">
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
         <item name="android:textSize">20sp</item>
     </style>
 
     <style name="TextAppearance.CategoryTitle.SettingsLib"
-           parent="@*android:style/TextAppearance.DeviceDefault.Body2" />
+           parent="@android:style/TextAppearance.DeviceDefault.Medium">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">14sp</item>
+    </style>
 
     <style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
         <item name="android:switchMinWidth">52dp</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 8034710..6bf288b 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -50,6 +50,6 @@
         <item name="android:clipToPadding">true</item>
         <item name="android:clipChildren">true</item>
 
-        <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+        <item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index 25f9514..18af1f9 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -20,4 +20,5 @@
     <dimen name="app_preference_padding_start">?android:attr/listPreferredItemPaddingStart</dimen>
     <dimen name="app_icon_min_width">56dp</dimen>
     <dimen name="two_target_min_width">72dp</dimen>
+    <dimen name="settingslib_dialogCornerRadius">8dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
index 6f25177..2d881d1 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
@@ -35,7 +35,7 @@
         <!-- TODO(b/189308264): fix the crash in Android R if set the attributes:
              <item name="colorAccent">@*android:color/accent_device_default_light</item>
              <item name="android:colorBackground">@color/settingslib_dialog_background</item>
-             <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+             <item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
         -->
         <item name="android:windowSoftInputMode">adjustResize</item>
         <item name="android:clipToPadding">true</item>
diff --git a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
index 65869b5..b6ca41f 100644
--- a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
+++ b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
@@ -16,8 +16,7 @@
   -->
 <resources>
     <style name="TextAppearance.TopIntroText"
-           parent="@*android:style/TextAppearance.DeviceDefault">
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+           parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textSize">14sp</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target_divider.xml b/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target_divider.xml
index f21e51c..4641421 100644
--- a/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target_divider.xml
+++ b/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target_divider.xml
@@ -22,6 +22,8 @@
     android:layout_height="match_parent"
     android:gravity="start|center_vertical"
     android:orientation="horizontal"
+    android:paddingStart="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingLeft="?android:attr/listPreferredItemPaddingEnd"
     android:paddingTop="16dp"
     android:paddingBottom="16dp">
     <View
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
index 44f6f54..9dcb5bc 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
@@ -52,9 +52,9 @@
         }
 
         return (VERSION.CODENAME.equals("REL") && VERSION.SDK_INT >= 31)
-                || (VERSION.CODENAME.length() == 1
-                && VERSION.CODENAME.compareTo("S") >= 0
-                && VERSION.CODENAME.compareTo("Z") <= 0);
+                || (VERSION.CODENAME.length() >= 1
+                && VERSION.CODENAME.toUpperCase().charAt(0) >= 'S'
+                && VERSION.CODENAME.toUpperCase().charAt(0) <= 'Z');
     }
 
     private BuildCompatUtils() {}
diff --git a/packages/SettingsLib/res/layout/preference_widget_primary_switch.xml b/packages/SettingsLib/res/layout/preference_widget_primary_switch.xml
new file mode 100644
index 0000000..5de268d
--- /dev/null
+++ b/packages/SettingsLib/res/layout/preference_widget_primary_switch.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<Switch
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/switchWidget"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:minWidth="@dimen/two_target_min_width"
+    android:gravity="center_vertical"
+    android:clickable="false" />
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml b/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
new file mode 100644
index 0000000..69df751
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <include layout="@layout/restricted_icon"/>
+
+    <include layout="@layout/preference_widget_primary_switch"/>
+</merge>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 99edaff..51e954f 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Kan nie skandeer vir netwerke nie"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Geen/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Geen"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-persoonlik"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-persoonlik"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-onderneming"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-onderneming"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-onderneming"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-onderneming"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-onderneming"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-persoonlik"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-persoonlik"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Geen/verbeterde oopsekuriteit"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Verbeterde oopsekuriteit"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-onderneming 192-bis"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Gestoor"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Ontkoppel"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Gedeaktiveer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index a6aa725..b0ce875 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ለአውታረመረቦች መቃኘት አይቻልም"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"ምንም/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"የለም"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-የግል"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-የግል"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-የግል"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-የድርጅት"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-የድርጅት"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-የድርጅት"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-የድርጅት"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-የድርጅት"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"መተላለፊያ"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-የግል"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-የግል"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"የለም/የተሻሻለ ክፍት"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"የተሻሻለ ክፈት"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-የድርጅት 192-ቢት"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ተቀምጧል"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ተቋርጧል"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ተሰናክሏል"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 24d9873..ba6bd70 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"لا يمكن فحص الشبكات"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"‏بدون أمان/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"بلا أمان"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"نقطة مرور"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"بدون أمان/مفتوحة ومحسّنة"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"مفتوحة ومحسّنة"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"‏WPA3-Enterprise ‏192 بت"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"تم الحفظ"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"غير متصلة"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"غير مفعّلة"</string>
@@ -511,7 +538,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"المنبّهات والتذكيرات"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"السماح بضبط المنبّهات والتذكيرات"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"المنبّهات والتذكيرات"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"عليك السماح لهذا التطبيق بضبط المنبّهات وتحديد مواعيد للإجراءات الحساسة زمنيًا. يسمح هذا الأذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من شحن البطارية.\n\nإذا كان هذا الإذن غير مسموح به، لن تعمل الأحداث المستندة إلى وقت والمنبّهات الحالية التي يحدِّد هذا التطبيق موعدها."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات لتنفيذها في الوقت المناسب. ويسمح هذا الإذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من البطارية.\n\nفي حال عدم تفعيل هذا الإذن، لن تعمل المنبهات الحالية والأحداث المستندة إلى الوقت المضبوطة في هذا التطبيق."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"جدول زمني، جدولة، منبّه، تذكير، ساعة"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"تفعيل"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل ميزة \"عدم الإزعاج\""</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 6dd95a3..82c6bc0 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"নেটৱৰ্ক বিচাৰি স্কেন কৰিব পৰা নাই"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"৮০২.১ গুণ"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-১৯২"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"নাই"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"পাছপইণ্ট"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise ১৯২-বিট"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ছেভ কৰি থোৱা নেটৱৰ্কসমূহ"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"সংযোগ বিচ্ছিন্ন"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"নিষ্ক্ৰিয় হৈ আছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 0c91459..d6c4c88 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Şəbəkə axtarmaq olmur"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Heç biri/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Dəst-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Heç biri"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Şəxsi"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Şəxsi"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Şəxsi"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Müəssisə"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Müəssisə"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Müəssisə"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Müəssisə"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Müəssisə"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Keçid nöqtəsi"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Şəxsi"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Şəxsi"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Heç biri/Genişləndirilmiş Açılış"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Genişləndirilmiş Açılış"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Müəssisə 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Yadda saxlanılan"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Bağlantı kəsildi"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Deaktiv"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 4db3717..da65227 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nije moguće skenirati mreže"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ništa/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nema"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ništa/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192-bitni"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Sačuvano"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Veza je prekinuta"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 604610b..3126f52 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Не атрымлiваецца выканаць сканаванне для сетак"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Няма/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Няма"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Няма/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-бітнае шыфраванне"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Захавана"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Адключана"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Адключана"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 39a1ff2..5a57d44 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Не може да се сканира за мрежи"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Няма/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Няма"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Няма/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Стандарт за сигурност Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192-битова защита"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Запазено"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Няма връзка"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Деактивирани"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 0fd9ae5..bac2f36 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"নেটওয়ার্কগুলির জন্য স্ক্যান করা যাবে না"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"কোনওটাই নয়/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"কোনও কিছুই নয়"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"পাসপয়েন্ট"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"কোনওটাই নয়/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"সংরক্ষিত"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"কানেকশন নেই"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"অক্ষম হয়েছে"</string>
@@ -252,8 +279,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 +311,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 5b51efa..483d3b6 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Ne može skenirati mreže"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ništa/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ništa"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ništa/poboljšano otvaranje"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Poboljšano otvaranje"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bitni"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Sačuvano"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Nije povezano"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 948d3a0..1cffe78 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"No es poden cercar xarxes"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Cap/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Cap"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Cap / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise de 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Desat"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Desconnectada"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Desactivat"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 0e15848..dd41dbc 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nelze hledat sítě"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Žádné/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Žádné"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2 Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Žádné/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 bitů"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Uloženo"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Odpojeno"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Vypnuto"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 4fdf435..f895636 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Der kan ikke søges efter netværk"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ingen/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ingen"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ingen/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Gemt"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Afbrudt"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Deaktiveret"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 489c7c7..520ac98 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Netzwerkscan nicht möglich"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Keine/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite B 192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Keine"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Keinse/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 Bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Gespeichert"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Nicht verbunden"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Deaktiviert"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 8cd8387..d95f5b5 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Δεν είναι δυνατή η σάρωση για δίκτυα"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Καμία/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Καμία"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Προσωπικό"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Προσωπικό"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Προσωπικό"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Εταιρικό"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Εταιρικό"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Εταιρικό"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Εταιρικό"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Εταιρικό"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Προσωπικό"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Προσωπικό"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Καμία/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Εταιρικό 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Αποθηκευμένο"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Αποσυνδεδεμένο"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Απενεργοποιημένο"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index a6f1bfc..1273a19 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Can\'t scan for networks"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"None"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Saved"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Disconnected"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 4ad9894..70fdaac 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Can\'t scan for networks"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"None"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Saved"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Disconnected"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index a6f1bfc..1273a19 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Can\'t scan for networks"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"None"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Saved"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Disconnected"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index a6f1bfc..1273a19 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Can\'t scan for networks"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"None"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Saved"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Disconnected"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index c8a7363..56267bb 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‎Can\'t scan for networks‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎WEP‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‏‎WPA‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎WPA2‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎WPA/WPA2‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‎802.1x‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎WPA-EAP‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎RSN-EAP‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎WPA3‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎WPA2/WPA3‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎None/OWE‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎OWE‎‏‎‎‏‎"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎Suite-B-192‎‏‎‎‏‎"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎None‎‏‎‎‏‎"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎WEP‎‏‎‎‏‎"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎WPA-Personal‎‏‎‎‏‎"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎WPA2-Personal‎‏‎‎‏‎"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎WPA/WPA2-Personal‎‏‎‎‏‎"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‎WPA/WPA2/WPA3-Enterprise‎‏‎‎‏‎"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎WPA-Enterprise‎‏‎‎‏‎"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎WPA/WPA2-Enterprise‎‏‎‎‏‎"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‎‎WPA2/WPA3-Enterprise‎‏‎‎‏‎"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎WPA3-Enterprise‎‏‎‎‏‎"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎Passpoint‎‏‎‎‏‎"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎WPA3-Personal‎‏‎‎‏‎"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎WPA2/WPA3-Personal‎‏‎‎‏‎"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎None/Enhanced Open‎‏‎‎‏‎"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎Enhanced Open‎‏‎‎‏‎"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎WPA3-Enterprise 192-bit‎‏‎‎‏‎"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎Saved‎‏‎‎‏‎"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎Disconnected‎‏‎‎‏‎"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎Disabled‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 27fbf44..30294ce 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"No se pueden buscar las redes."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ninguno/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ninguna"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2 Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ninguno/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Guardado"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Desconectado"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Inhabilitada"</string>
@@ -426,7 +453,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver colores con más exactitud&lt;/li&gt; &lt;li&gt; Quitar colores para tener un enfoque más claro&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver colores con más exactitud&lt;/li&gt; &lt;li&gt;&amp;nbsp;Quitar colores para tener un enfoque más claro&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f33a29d..fbdb37a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"No se puede buscar redes."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ninguna/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ninguna"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ninguna/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise de 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Guardado"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Desconectado"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Inhabilitado"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 0ede248..ca83bf8 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Võrke ei saa kontrollida"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Puudub/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Puudub"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Puudub / Täiustatud avamine"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Täiustatud avamine"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise (192-bitine)"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Salvestatud"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Pole ühendatud"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Keelatud"</string>
@@ -507,7 +534,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmid ja meeldetuletused"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Luba alarmide ja meeldetuletuste määramine"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmid ja meeldetuletused"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata alarme ja ajastada kiire tähtajaga toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad alarmid ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata alarme ja ajastada ajakriitilisi toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad alarmid ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ajakava, äratus, meeldetuletus, kell"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Lülita sisse"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Valiku Mitte segada sisselülitamine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 1f8d616..3ae9fa3 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Ezin dira sareak bilatu"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Bat ere ez / OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Bat ere ez"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Bat ere ez / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192 bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Gordeta"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Deskonektatuta"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Desgaituta"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index b53a83d..6ceea96 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"اسکن شبکه‌ها امکان‌پذیر نیست"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"‏هیچ‌کدام/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"خالی"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"‏هیچ‌کدام/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"‏WPA3-Enterprise ‏۱۹۲ بیت"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ذخیره‌شده"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"اتصال قطع شد"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"غیرفعال شد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index e116a19..57780e1 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Verkkoja ei voi etsiä."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ei mitään / OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ei mitään"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ei mitään / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"192-bittinen WPA3-Enterprise"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Tallennettu"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Yhteys katkaistu"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Pois päältä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 2291c6f..dbd3f71 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Impossible de rechercher des réseaux."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Aucun/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Aucune"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Aucun/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Enregistré"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Déconnecté"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Désactivés"</string>
@@ -155,7 +182,7 @@
     <string name="running_process_item_user_label" msgid="3988506293099805796">"Utilisateur : <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="3631650616557252926">"Certaines préférences par défaut définies"</string>
     <string name="launch_defaults_none" msgid="8049374306261262709">"Aucune préférence par défaut définie"</string>
-    <string name="tts_settings" msgid="8130616705989351312">"Synthèse vocale"</string>
+    <string name="tts_settings" msgid="8130616705989351312">"Paramètres de synthèse vocale"</string>
     <string name="tts_settings_title" msgid="7602210956640483039">"Synthèse vocale"</string>
     <string name="tts_default_rate_title" msgid="3964187817364304022">"Cadence"</string>
     <string name="tts_default_rate_summary" msgid="3781937042151716987">"Vitesse à laquelle le texte est énoncé"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 3abd211..6c53ade 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Impossible de rechercher des réseaux."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Aucune/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Aucune"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Aucun/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Enregistré"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Déconnecté"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Désactivé"</string>
@@ -284,7 +311,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
-    <string name="wifi_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 Wi-Fi où le changement aléatoire d\'adresse MAC est activé."</string>
+    <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 bbf8e74..7de607f 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Non se poden explorar redes"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ningunha"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise de 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Gardada"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Rede desconectada"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Desactivadas"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9fc70cf..f8b1123 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"નેટવર્ક્સ માટે સ્કૅન કરી શકતા નથી"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"એકપણ નહીં/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"સ્યૂટ-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"કોઈ નહીં"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-વ્યક્તિગત"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-વ્યક્તિગત"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-વ્યક્તિગત"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-એન્ટરપ્રાઇઝ"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-એન્ટરપ્રાઇઝ"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-એન્ટરપ્રાઇઝ"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-એન્ટરપ્રાઇઝ"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-એન્ટરપ્રાઇઝ"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-વ્યક્તિગત"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-વ્યક્તિગત"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"એકપણ નહીં/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-એન્ટરપ્રાઇઝ 192-બિટ"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"સાચવેલા"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ડિસ્કનેક્ટ કર્યું"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"અક્ષમ કર્યો"</string>
@@ -252,8 +279,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 +311,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 c065f9a..0c115ca 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"नेटवर्क के लिए स्‍कैन नहीं कर सकता"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"कोई नहीं/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"कोई नहीं"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-निजी"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-निजी"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-निजी"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-एंटरप्राइज़"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-एंटरप्राइज़"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-एंटरप्राइज़"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-एंटरप्राइज़"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-एंटरप्राइज़"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"पासपॉइंट"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-निजी"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-निजी"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"कोई नहीं/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-एंटरप्राइज़ 192-बिट"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"सेव किया गया"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"डिसकनेक्ट किया गया"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"अक्षम"</string>
@@ -527,7 +554,7 @@
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
     <string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
-    <string name="storage_category" msgid="2287342585424631813">"डिवाइस की मेमोरी"</string>
+    <string name="storage_category" msgid="2287342585424631813">"डिवाइस का स्टोरेज"</string>
     <string name="shared_data_title" msgid="1017034836800864953">"शेयर किया गया डेटा"</string>
     <string name="shared_data_summary" msgid="5516326713822885652">"शेयर किए गए डेटा को देखें और उसमें बदलाव करें"</string>
     <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"इस उपयोगकर्ता के साथ किसी तरह का डेटा शेयर नहीं किया गया है."</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 0727c83..f671e8c 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Skeniranje mreža nije moguće"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ništa/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nema"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ništa/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192-bitna sigurnost"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Spremljeno"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Nije povezano"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 12a81a6..3a703a9 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nem lehet beolvasni a hálózatokat"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nincs/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nincs"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nincs/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Mentve"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Leválasztva"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Letiltva"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 1fd6c5f..10f05b0 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Հնարավոր չէ սկանավորել ցանցերը"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Կարգավորված չէ/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ոչ մեկը"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Կարգավորված չէ/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Պահված է"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Կապ չկա"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Անջատված"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 2dba96a..7b4c9b6 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -23,7 +23,7 @@
   <string-array name="wifi_status">
     <item msgid="1596683495752107015"></item>
     <item msgid="3288373008277313483">"Memindai..."</item>
-    <item msgid="6050951078202663628">"Menyambung…"</item>
+    <item msgid="6050951078202663628">"Menghubungkan…"</item>
     <item msgid="8356618438494652335">"Mengautentikasi…"</item>
     <item msgid="2837871868181677206">"Mendapatkan alamat IP…"</item>
     <item msgid="4613015005934755724">"Terhubung"</item>
@@ -37,7 +37,7 @@
   <string-array name="wifi_status_with_ssid">
     <item msgid="5969842512724979061"></item>
     <item msgid="1818677602615822316">"Memindai..."</item>
-    <item msgid="8339720953594087771">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8339720953594087771">"Menghubungkan ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="3028983857109369308">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="4287401332778341890">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 3480411..9eacc6c 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -21,26 +21,53 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Tidak dapat memindai jaringan"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Tidak Ada/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Tidak ada"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Tidak Ada/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Disimpan"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Terputus"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Nonaktif"</string>
     <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Kegagalan Konfigurasi IP"</string>
-    <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Tidak tersambung karena jaringan berkualitas rendah"</string>
+    <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Tidak terhubung karena jaringan berkualitas rendah"</string>
     <string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"Kegagalan Sambungan Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="6892387079613226738">"Masalah autentikasi"</string>
-    <string name="wifi_cant_connect" msgid="5718417542623056783">"Tidak dapat tersambung"</string>
-    <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"Tidak dapat tersambung ke \'<xliff:g id="AP_NAME">%1$s</xliff:g>\'"</string>
+    <string name="wifi_cant_connect" msgid="5718417542623056783">"Tidak dapat terhubung"</string>
+    <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"Tidak dapat terhubung ke \'<xliff:g id="AP_NAME">%1$s</xliff:g>\'"</string>
     <string name="wifi_check_password_try_again" msgid="8817789642851605628">"Periksa sandi dan coba lagi"</string>
     <string name="wifi_not_in_range" msgid="1541760821805777772">"Tidak dalam jangkauan"</string>
-    <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan tersambung otomatis"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan terhubung otomatis"</string>
     <string name="wifi_no_internet" msgid="1774198889176926299">"Tidak ada akses internet"</string>
     <string name="saved_network" msgid="7143698034077223645">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Terhubung ke jaringan berbayar"</string>
-    <string name="connected_via_network_scorer" msgid="7665725527352893558">"Tersambung otomatis melalui %1$s"</string>
-    <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Otomatis tersambung melalui penyedia rating jaringan"</string>
+    <string name="connected_via_network_scorer" msgid="7665725527352893558">"Terhubung otomatis melalui %1$s"</string>
+    <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Otomatis terhubung melalui penyedia rating jaringan"</string>
     <string name="connected_via_passpoint" msgid="7735442932429075684">"Terhubung melalui %1$s"</string>
-    <string name="connected_via_app" msgid="3532267661404276584">"Tersambung melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_app" msgid="3532267661404276584">"Terhubung melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="available_via_passpoint" msgid="1716000261192603682">"Tersedia melalui %1$s"</string>
     <string name="tap_to_sign_up" msgid="5356397741063740395">"Ketuk untuk mendaftar"</string>
     <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Tidak ada internet"</string>
@@ -49,10 +76,10 @@
     <string name="wifi_status_no_internet" msgid="3799933875988829048">"Tidak ada internet"</string>
     <string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Perlu login"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"Titik akses penuh untuk sementara"</string>
-    <string name="connected_via_carrier" msgid="1968057009076191514">"Tersambung melalui %1$s"</string>
+    <string name="connected_via_carrier" msgid="1968057009076191514">"Terhubung melalui %1$s"</string>
     <string name="available_via_carrier" msgid="465598683092718294">"Tersedia melalui %1$s"</string>
     <string name="osu_opening_provider" msgid="4318105381295178285">"Membuka <xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g>"</string>
-    <string name="osu_connect_failed" msgid="9107873364807159193">"Tidak dapat tersambung"</string>
+    <string name="osu_connect_failed" msgid="9107873364807159193">"Tidak dapat terhubung"</string>
     <string name="osu_completing_sign_up" msgid="8412636665040390901">"Menyelesaikan pendaftaran…"</string>
     <string name="osu_sign_up_failed" msgid="5605453599586001793">"Tidak dapat menyelesaikan pendaftaran. Ketuk untuk mencoba lagi."</string>
     <string name="osu_sign_up_complete" msgid="7640183358878916847">"Pendaftaran selesai. Menyambungkan…"</string>
@@ -66,7 +93,7 @@
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Sambungan terputus"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Memutus sambungan..."</string>
-    <string name="bluetooth_connecting" msgid="5871702668260192755">"Menyambung…"</string>
+    <string name="bluetooth_connecting" msgid="5871702668260192755">"Menghubungkan…"</string>
     <string name="bluetooth_connected" msgid="8065345572198502293">"Terhubung<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_pairing" msgid="4269046942588193600">"Menyandingkan..."</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Terhubung (tanpa ponsel)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -96,12 +123,12 @@
     <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
     <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Alat Bantu Dengar"</string>
     <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Terhubung ke Alat Bantu Dengar"</string>
-    <string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Tersambung ke media audio"</string>
-    <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Tersambung ke audio ponsel"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Terhubung ke media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Terhubung ke audio ponsel"</string>
     <string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Sambungkan ke server transfer file"</string>
-    <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"Tersambung ke peta"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"Terhubung ke peta"</string>
     <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Terhubung ke SAP"</string>
-    <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Tidak tersambung kepada server transfer file"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Tidak terhubung kepada server transfer file"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Terhubung ke perangkat masukan"</string>
     <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Terhubung ke perangkat untuk akses internet"</string>
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Berbagi koneksi internet lokal dengan perangkat"</string>
@@ -116,7 +143,7 @@
     <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sambungkan"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAMBUNGKAN"</string>
     <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Batal"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Penyandingan memberi akses ke kontak dan histori panggilan saat tersambung"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Penyandingan memberi akses ke kontak dan histori panggilan saat terhubung"</string>
     <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Tidak dapat menyambungkan ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Tidak dapat menyambungkan ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g> karena PIN atau kode sandi salah."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Tidak dapat berkomunikasi dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -133,7 +160,7 @@
     <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Kiri - baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Kanan - baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi tidak aktif."</string>
-    <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi tidak tersambung."</string>
+    <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi tidak terhubung."</string>
     <string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Wi-Fi satu baris."</string>
     <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi dua baris"</string>
     <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi tiga baris."</string>
@@ -205,7 +232,7 @@
     <string name="tethering_settings_not_available" msgid="266821736434699780">"Setelan Penambatan tidak tersedia untuk pengguna ini"</string>
     <string name="apn_settings_not_available" msgid="1147111671403342300">"Setelan Nama Titik Akses tidak tersedia untuk pengguna ini"</string>
     <string name="enable_adb" msgid="8072776357237289039">"Debugging USB"</string>
-    <string name="enable_adb_summary" msgid="3711526030096574316">"Mode debug ketika USB tersambung"</string>
+    <string name="enable_adb_summary" msgid="3711526030096574316">"Mode debug ketika USB terhubung"</string>
     <string name="clear_adb_keys" msgid="3010148733140369917">"Cabut otorisasi debug USB"</string>
     <string name="enable_adb_wireless" msgid="6973226350963971018">"Proses debug nirkabel"</string>
     <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Mode debug saat Wi-Fi terhubung"</string>
@@ -217,19 +244,19 @@
     <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Sambungkan perangkat dengan kode penyambungan"</string>
     <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Sambungkan perangkat baru menggunakan kode enam digit"</string>
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"Perangkat disambungkan"</string>
-    <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Saat ini tersambung"</string>
+    <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Saat ini terhubung"</string>
     <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Detail perangkat"</string>
     <string name="adb_device_forget" msgid="193072400783068417">"Lupakan"</string>
     <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Sidik jari perangkat: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
     <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Sambungan gagal"</string>
-    <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Pastikan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tersambung ke jaringan yang tepat"</string>
+    <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Pastikan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> terhubung ke jaringan yang tepat"</string>
     <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Sambungkan dengan perangkat"</string>
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Kode penyambungan Wi-Fi"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Penyambungan perangkat gagal"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Pastikan perangkat terhubung ke jaringan yang sama."</string>
     <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Sambungkan perangkat melalui Wi‑Fi dengan memindai Kode QR"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Menyambungkan perangkat…"</string>
-    <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Gagal menyambungkan perangkat. Kode QR salah, atau perangkat tidak tersambung ke jaringan yang sama."</string>
+    <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Gagal menyambungkan perangkat. Kode QR salah, atau perangkat tidak terhubung ke jaringan yang sama."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Alamat IP &amp; Port"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Memindai kode QR"</string>
     <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Sambungkan perangkat melalui Wi‑Fi dengan memindai Kode QR"</string>
@@ -335,7 +362,7 @@
     <string name="pointer_location" msgid="7516929526199520173">"Lokasi penunjuk"</string>
     <string name="pointer_location_summary" msgid="957120116989798464">"Hamparan layar menampilkan data sentuhan saat ini"</string>
     <string name="show_touches" msgid="8437666942161289025">"Tampilkan ketukan"</string>
-    <string name="show_touches_summary" msgid="3692861665994502193">"Tampilkan masukan untuk ketukan"</string>
+    <string name="show_touches_summary" msgid="3692861665994502193">"Tampilkan efek visual untuk ketukan"</string>
     <string name="show_screen_updates" msgid="2078782895825535494">"Lihat pembaruan permukaan"</string>
     <string name="show_screen_updates_summary" msgid="2126932969682087406">"Sorot seluruh permukaan jendela saat diperbarui"</string>
     <string name="show_hw_screen_updates" msgid="2021286231267747506">"Tampilkan update tampilan"</string>
@@ -507,7 +534,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm dan pengingat"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Izinkan menyetel alarm dan pengingat"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm &amp; pengingat"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Izinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan berjangka waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berjangka waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Izinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan yang sensitif waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berbasis waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"jadwal, alarm, pengingat, jam"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktifkan"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktifkan mode Jangan Ganggu"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 8b56f6a..d67b872 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Ekki er hægt að leita að netum"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ekkert/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ekkert"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Aðgangspunktur"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ekkert/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bita"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Vistað"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Aftengt"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Óvirkt"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index def0909..27f5c3c 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Impossibile cercare reti"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nessuna/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nessuna"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nessuna/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise a 192 bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Salvata"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Non connessa"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Disattivata"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fba3aeb..371d20a 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"לא ניתן לסרוק לאיתור רשתות"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"‏ללא/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ללא"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"‏Passpoint : פרוטוקול Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"‏ללא/רשת Wi-Fi עם אבטחת OWE"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"‏רשת Wi-Fi עם אבטחת OWE"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"נשמר"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"מנותקת"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"מושבת"</string>
@@ -252,7 +279,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>
-    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‏רנדומיזציה של כתובות MAC בלי חיבור יציב ל-Wi-Fi"</string>
+    <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>
@@ -426,7 +453,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏ניתן לשנות את האופן שבו צבעים מוצגים במכשיר. שינוי כזה עשוי לעזור:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; להבחין בצבעים בצורה יותר מדויקת&lt;/li&gt; &lt;li&gt; להסיר צבעים מסוימים כדי להתמקד&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏ניתן לשנות את האופן שבו צבעים מוצגים במכשיר. שינוי כזה עשוי לעזור:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;להבחין בצבעים בצורה יותר מדויקת&lt;/li&gt; &lt;li&gt;&amp;nbsp;להסיר צבעים מסוימים כדי להתמקד&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 1a7d9ba..0d85974 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ネットワークをスキャンできません"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"なし / OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"なし"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"なし / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 ビット"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"保存済み"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"未接続"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"無効"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 33d3e65..572d109 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ქსელების სკანირება არა არის შესაძლებელი"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"არცერთი/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"არცერთი"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"არცერთი/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-ბიტიანი"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"დამახსოვრებულია"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"კავშირი გაწყვეტილია"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"გამორთულია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 62dff735..229ed45 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Желілерді шолу мүмкін емес"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Жоқ/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Жоқ"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Жоқ/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 бит"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Сақталды"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Ажыратылған"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Өшірілген"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 0b23e68..efc422c 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"មិន​អាច​វិភាគ​រក​បណ្ដាញ"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"គ្មាន/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"គ្មាន"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"គ្មាន/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 ប៊ីត"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"បាន​រក្សាទុក"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"បាន​ផ្ដាច់"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"បាន​បិទ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 99fd1d3..91ee100 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ನೆಟ್‌ವರ್ಕ್‌ಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"ಯಾವುದೂ ಇಲ್ಲ/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ಯಾವುದೂ ಇಲ್ಲ"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-ವೈಯಕ್ತಿಕ"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2- ವೈಯಕ್ತಿಕ"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-ವೈಯಕ್ತಿಕ"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-ಎಂಟರ್‌ಪ್ರೈಸ್"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-ಎಂಟರ್‌ಪ್ರೈಸ್"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-ಎಂಟರ್‌ಪ್ರೈಸ್"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-ಎಂಟರ್‌ಪ್ರೈಸ್"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-ಎಂಟರ್‌ಪ್ರೈಸ್"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-ವೈಯಕ್ತಿಕ"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-ವೈಯಕ್ತಿಕ"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"ಯಾವುದೂ ಇಲ್ಲ/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-ಎಂಟರ್‌ಪ್ರೈಸ್ 192-ಬಿಟ್"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ಉಳಿಸಲಾಗಿದೆ"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
@@ -252,8 +279,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 +311,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 421c60f..455a0ab 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"네트워크를 검색할 수 없습니다."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"없음/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"없음"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"없음/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192비트"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"저장됨"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"연결 끊김"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"사용 중지됨"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index bdc4939..74585da 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Түйүндөрдү издөө мүмкүн эмес"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Жок/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Жок"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Жок/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 бит"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Сакталды"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Ажыратылды"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Өчүрүлгөн"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 91e5c00..5490543 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ບໍ່ສາມາດກວດຫາເຄືອຂ່າຍໄດ້"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ບໍ່ໃຊ້"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ບັນ​ທຶກແລ້ວ"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ປິດການນຳໃຊ້"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 9887a93..b53e1b0 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nepavyksta nuskaityti tinklų"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA / WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2 / WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nėra / OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nėra"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA / „WPA2-Personal“"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA / WPA2 / „WPA3-Enterprise“"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA / „WPA2-Enterprise“"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2 / „WPA3-Enterprise“"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2 / „WPA3-Personal“"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nėra / „Enhanced Open“"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"„WPA3-Enterprise“, 192 bitų"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Išsaugotas"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Neprisijungta"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Neleidžiama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 81a566c..053e97e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nevar skenēt tīklus"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nav/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nav"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nav/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192 bitu"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Saglabāts"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Savienojums pārtraukts"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Atspējots"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index ed64960..5d348b6 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Не може да скенира за мрежи"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Нема/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Нема"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Нема/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-битна"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Зачувано"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Не е поврзано"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Оневозможено"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 660f4b6..b9e719b3 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"നെ‌റ്റ്‌വർക്കുകൾക്കായി സ്കാൻ ചെയ്യാനായില്ല"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"ഒന്നുമില്ല/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ഒന്നുമില്ല"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"പാസ്പോയിന്റ്"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"ഒന്നുമില്ല/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"സംരക്ഷിച്ചു"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"വിച്ഛേദിച്ചു"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"പ്രവർത്തനരഹിതമാക്കി"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 074b864..d905541 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Сүлжээнүүдийг скан хийх боломжгүй"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Хоосон/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Иж бүрдэл-Б-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Байхгүй"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Хувийн"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Хувийн"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Хувийн"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Байгууллага"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Байгууллага"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Байгууллага"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Байгууллага"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Байгууллага"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Хувийн"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Хувийн"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Хоосон/Сайжруулсан нээлт"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Сайжруулсан нээлт"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Байгууллага 192-бит"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Хадгалагдсан"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Салсан"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Идэвхгүйжүүлсэн"</string>
@@ -426,7 +453,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь танд дараахыг хийхийг хүссэн үед хэрэг болж магадгүй:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt;Танд төвлөрөхөд туслахын тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь танд дараахыг хийхийг хүссэн үед хэрэг болж магадгүй:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt;&amp;nbsp;Танд төвлөрөхөд туслахын тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 0b0a4a6..485f40a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"नेटवर्कसाठी स्कॅन करू शकत नाही"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"कोणतेही नाही/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"स्वीट-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"काहीही नाही"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-वैयक्तिक"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-वैयक्तिक"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-वैयक्तिक"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-एंटरप्राइझ"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-एंटरप्राइझ"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-एंटरप्राइझ"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-एंटरप्राइझ"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-एंटरप्राइझ"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"पासपॉइंट"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-वैयक्तिक"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-वैयक्तिक"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"कोणतीही नाही/एन्हान्स्ड ओपन"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"एन्हान्स्ड ओपन"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-एंटरप्राइझ 192-बिट"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"सेव्ह केले"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"डिस्कनेक्ट केले"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"अक्षम"</string>
@@ -252,8 +279,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 +311,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>
@@ -309,7 +334,7 @@
     <string name="adb_keys_warning_message" msgid="2968555274488101220">"तुम्ही पूर्वी ऑथोराइझ केलेल्या सर्व संगणकांवरुन USB डीबग करण्यासाठी अ‍ॅक्सेस रीव्होक करायचा?"</string>
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"विकास सेटिंग्जला अनुमती द्यायची?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"या सेटिंग्जचा हेतू फक्त विकास वापरासाठी आहे. त्यामुळे तुमचे डिव्हाइस आणि त्यावरील ॲप्लिकेशन ब्रेक होऊ शकतात किंवा नेहमीपेक्षा वेगळे वर्तन करू शकतात."</string>
-    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB वर अ‍ॅप्स पडताळून पाहा"</string>
+    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB वर अ‍ॅप्स पडताळून पहा"</string>
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"हानिकारक वर्तनासाठी ADB/ADT द्वारे इंस्टॉल अ‍ॅप्स तपासा."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"नावांशिवाय ब्‍लूटूथ डिव्‍हाइस (फक्‍त MAC पत्ते) दाखवले जातील"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"रिमोट डिव्हाइसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणाचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटूथ संपूर्ण आवाज वैशिष्ट्य बंद करते."</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 4390896..e054bd0 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Tidak boleh mengimbas untuk rangkaian"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Tiada/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Tiada"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Keselamatan OWE Tiada/Dipertingkat"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Keselamatan OWE Dipertingkat"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Disimpan"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Diputuskan sambungan"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Dinyahdayakan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 199d15c..ca7ffc9 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ကွန်ယက်များကို စကင်မလုပ်နိုင်ပါ"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"မရှိ/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"မရှိ"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"ဖြတ်သန်းခွင့်ပြုမှတ်"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"မရှိ/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"သိမ်းဆည်းပြီး"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ချိတ်ဆက်မထားပါ"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ပိတ်ထားသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 722f98f..d355ae5 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Kan ikke søke etter nettverk"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ingen/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ingen"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ingen / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Lagret"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Frakoblet"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Slått av"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a109c58..508222f 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"सञ्जालका लागि स्क्यान गर्न सक्दैन"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"८०२.१x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"कुनै पनि होइन/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"सुइट-B-१९२"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"छैन"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-पर्सनल"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-पर्सनल"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-पर्सनल"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-इन्टरप्राइज"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-इन्टरप्राइज"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-इन्टरप्राइज"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-इन्टरप्राइज"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-इन्टरप्राइज"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"पासपोइन्ट"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3 पर्सनल"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-पर्सनल"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"कुनै पनि होइन/इन्हान्स्ड ओपन"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"इन्हान्स्ड ओपन"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-इन्टरप्राइज १९२-बिट"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"सेभ गरिएको छ"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"डिस्कनेक्ट गरिएको छ"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"असक्षम पारियो"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 12a47bc..daef7e1 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Kan niet zoeken naar netwerken"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Geen/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Geen"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Geen/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Opgeslagen"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Verbinding verbroken"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Uitgezet"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index d047b17..dd0b1f2 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ନେଟ୍‌ୱର୍କଗୁଡ଼ିକୁ ଖୋଜିପାରୁନାହିଁ"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"କିଛି ନାହିଁ/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"କିଛି ନାହିଁ"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"ପାସପଏଣ୍ଟ"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"କିଛି ନାହିଁ/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-ବିଟ୍"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ସେଭ୍‌ ହୋଇଗଲା"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ବିଛିନ୍ନ କରାଯାଇଛି"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ଅକ୍ଷମ ହୋଇଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index a310dae..ccdfec3 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ਨੈਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਨਹੀਂ ਕਰ ਸਕਦਾ"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"ਕੋਈ ਨਹੀਂ/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ਕੋਈ ਨਹੀਂ"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-ਨਿੱਜੀ"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-ਨਿੱਜੀ"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-ਨਿੱਜੀ"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-ਐਂਟਰਪ੍ਰਾਈਜ਼"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-ਐਂਟਰਪ੍ਰਾਈਜ਼"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-ਐਂਟਰਪ੍ਰਾਈਜ਼"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-ਐਂਟਰਪ੍ਰਾਈਜ਼"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-ਐਂਟਰਪ੍ਰਾਈਜ਼"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"ਪਾਸ ਪੁਆਇੰਟ"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-ਨਿੱਜੀ"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-ਨਿੱਜੀ"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"ਕੋਈ ਨਹੀਂ/ਵਿਸਤ੍ਰਿਤ ਤੌਰ \'ਤੇ ਖੁੱਲ੍ਹਾ"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"ਵਿਸਤ੍ਰਿਤ ਤੌਰ \'ਤੇ ਖੁੱਲ੍ਹਾ"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-ਐਂਟਰਪ੍ਰਾਈਜ਼ 192-ਬਿਟ"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"ਰੱਖਿਅਤ ਕੀਤਾ"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ਡਿਸਕਨੈਕਟ ਹੋਇਆ"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ਅਯੋਗ ਬਣਾਇਆ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 011c895..7c656afe 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nie można wyszukać sieci."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Brak/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Brak"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Brak / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise (szyfrowanie 192-bitowe)"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Zapisana"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Rozłączono"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Wyłączona"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 6804c58..2356f41 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Não é possível verificar a existência de redes"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nenhum/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nenhuma"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nenhum/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Salva"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Desconectada"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Desativado"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 30dceaf0..43155a7 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Não é possível verificar redes"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nenhum/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nenhuma"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nenhum/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise de 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Guardada"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Desligada"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Desativado"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 6804c58..2356f41 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Não é possível verificar a existência de redes"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Nenhum/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Nenhuma"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Nenhum/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 bits"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Salva"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Desconectada"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Desativado"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 0cd7926..083c2b9 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nu se poate scana pentru rețele"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA / WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2 / WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Fără / OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Niciuna"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA / WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA / WPA2 / WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA / WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2 / WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2 / WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Fără / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise pe 192 biți"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Salvată"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Deconectat"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Dezactivată"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 418af9a..0a0fce34 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Не удалось начать поиск сетей."</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Не настроено/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Нет"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Не настроено/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 бита"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Сохранено"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Не подключено"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Отключено"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index ffe6472..5b30c81 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ජාල සඳහා පරිලෝකනය කළ නොහැක"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"නැත/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"කිසිවක් නැත"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"පාස්පොයින්ට්"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"නැත/වැඩි දියුණු කළ විවෘත"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"වැඩි දියුණු කළ විවෘත"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise බිටු-192"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"සුරකින ලදි"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"විසන්ධි විය"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"අබලයි"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 7e46d1c..0d929db 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Siete sa nedajú vyhľadávať"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA‑EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN‑EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Žiadne/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite‑B‑192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Žiadne"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA‑Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2‑Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2‑Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3‑Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA‑Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2‑Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3‑Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3‑Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3‑Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3‑Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Žiadne / Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3‑Enterprise (192‑bitové)"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Uložené"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Odpojené"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Vypnuté"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index d498ac2..7a559fc 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Ni mogoče iskati omrežij"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Brez/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Brez"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Brez/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"192-bitni WPA3-Enterprise"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Shranjeno"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Ni povezave"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Onemogočeno"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b004082..4a1eeff 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Nuk mund të skanojë për rrjete"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Asnjë/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Asnjë"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Asnjë/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 bitë"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"U ruajt"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Shkëputur"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Të çaktivizuara"</string>
@@ -252,8 +279,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 +311,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>
@@ -509,7 +534,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmet dhe alarmet rikujtuese"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Lejo caktimin e alarmeve dhe alarmeve rikujtuese"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmet dhe alarmet rikujtuese"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lejo që ky aplikacion të caktojë alarmet dhe të planifikojë veprime që kanë një afat të caktuar. Kjo lejon që aplikacioni të ekzekutohet në sfond, gjë që mund të përdorë më shumë bateri.\n\nNëse kjo leje është caktuar si joaktive, alarmet ekzistuese dhe ngjarjet me bazë kohore të planifikuara nga ky apliikacion nuk do të funksionojnë."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lejo që ky aplikacion të caktojë alarmet dhe të planifikojë veprime që kanë një afat të caktuar. Kjo mundëson që aplikacioni të ekzekutohet në sfond, gjë që mund të përdorë më shumë bateri.\n\nNëse kjo leje është caktuar si joaktive, alarmet ekzistuese dhe ngjarjet në bazë kohore të planifikuara nga ky aplikacion nuk do të funksionojnë."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planifiko, alarm, alarm rikujtues, ora"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktivizo"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktivizo \"Mos shqetëso\""</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 5bb65e5..0359833 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Није могуће скенирати мреже"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Ништа/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Нема"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Ништа/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192-битни"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Сачувано"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Веза је прекинута"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Онемогућено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index cee8d53..a0b92a2 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Det går inte att söka efter nätverk"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Inget/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Ingen"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Inget/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bitar"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Sparat"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Frånkopplad"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Inaktiverad"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 4748118..76136c8 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Haiwezi kutambaza mitandao"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Hamna/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Hamna"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Hamna/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Imehifadhiwa"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Hujaunganishwa"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Imezimwa"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 2f25722..185104f 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"நெட்வொர்க்குகளுக்கு ஸ்கேன் செய்யப்படவில்லை"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"எதுவுமில்லை/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ஏதுமில்லை"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"எதுவுமில்லை/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"சேமிக்கப்பட்டது"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"தொடர்பு துண்டிக்கப்பட்டது"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"முடக்கப்பட்டது"</string>
@@ -84,7 +111,7 @@
     <string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"செயலில் உள்ளது"</string>
     <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"மீடியா ஆடியோ"</string>
     <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ஃபோன் அழைப்புகள்"</string>
-    <string name="bluetooth_profile_opp" msgid="6692618568149493430">"கோப்பு இடமாற்றம்"</string>
+    <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ஃபைல் இடமாற்றம்"</string>
     <string name="bluetooth_profile_hid" msgid="2969922922664315866">"உள்ளீட்டுச் சாதனம்"</string>
     <string name="bluetooth_profile_pan" msgid="1006235139308318188">"இணைய அணுகல்"</string>
     <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"தொடர்புப் பகிர்தல்"</string>
@@ -98,10 +125,10 @@
     <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"செவித்துணை கருவிகளுடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
-    <string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"கோப்பைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ஃபைலைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"வரைபடத்துடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"SAP உடன் இணைக்கப்பட்டது"</string>
-    <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"கோப்பு இடமாற்றும் சேவையகத்துடன் இணைக்கப்படவில்லை"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"ஃபைல் இடமாற்றும் சேவையகத்துடன் இணைக்கப்படவில்லை"</string>
     <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"உள்ளீட்டுச் சாதனத்துடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"சாதனத்துடன் இணைந்தது"</string>
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"சாதனத்துடன் உள்ளூர் இண்டர்நெட்டைப் பகிர்தல்"</string>
@@ -110,7 +137,7 @@
     <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"சிம் அணுகலுக்குப் பயன்படுத்தும்"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="7324694226276491807">"மீடியாவின் ஆடியோவிற்குப் பயன்படுத்து"</string>
     <string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"மொபைல் ஆடியோவைப் பயன்படுத்து"</string>
-    <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"கோப்பு பரிமாற்றத்திற்காகப் பயன்படுத்து"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ஃபைல் பரிமாற்றத்திற்காகப் பயன்படுத்து"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"உள்ளீட்டுக்குப் பயன்படுத்து"</string>
     <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"செவித்துணை கருவிகளுக்குப் பயன்படுத்தவும்"</string>
     <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"இணை"</string>
@@ -412,11 +439,11 @@
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string>
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView செயல்படுத்தலை அமை"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"இனி இந்தத் தேர்வைப் பயன்படுத்த முடியாது. மீண்டும் முயலவும்."</string>
-    <string name="convert_to_file_encryption" msgid="2828976934129751818">"கோப்பு முறைமையாக்கத்திற்கு மாற்று"</string>
+    <string name="convert_to_file_encryption" msgid="2828976934129751818">"ஃபைல் முறைமையாக்கத்திற்கு மாற்று"</string>
     <string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"மாற்று…"</string>
-    <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"ஏற்கனவே கோப்பு என்க்ரிப்ட் செய்யப்பட்டது"</string>
-    <string name="title_convert_fbe" msgid="5780013350366495149">"கோப்பு சார்ந்த முறைமையாக்கத்திற்கு மாற்றுதல்"</string>
-    <string name="convert_to_fbe_warning" msgid="34294381569282109">"தரவுப் பகிர்வை, கோப்பு சார்ந்த முறைமையாக்கத்திற்கு மாற்றவும்.\n !!எச்சரிக்கை!! இது எல்லா தரவையும் அழிக்கும்.\n இது ஆல்பா நிலை அம்சமாக இருப்பதால் சரியாகச் செயல்படாமல் போகக்கூடும்.\n தொடர, \'அழித்து, மாற்று…\' என்பதை அழுத்தவும்."</string>
+    <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"ஏற்கனவே ஃபைல் என்க்ரிப்ட் செய்யப்பட்டது"</string>
+    <string name="title_convert_fbe" msgid="5780013350366495149">"ஃபைல் சார்ந்த முறைமையாக்கத்திற்கு மாற்றுதல்"</string>
+    <string name="convert_to_fbe_warning" msgid="34294381569282109">"தரவுப் பகிர்வை, ஃபைல் சார்ந்த முறைமையாக்கத்திற்கு மாற்றவும்.\n !!எச்சரிக்கை!! இது எல்லா தரவையும் அழிக்கும்.\n இது ஆல்பா நிலை அம்சமாக இருப்பதால் சரியாகச் செயல்படாமல் போகக்கூடும்.\n தொடர, \'அழித்து, மாற்று…\' என்பதை அழுத்தவும்."</string>
     <string name="button_convert_fbe" msgid="1159861795137727671">"அழித்து மாற்று…"</string>
     <string name="picture_color_mode" msgid="1013807330552931903">"படத்தின் வண்ணப் பயன்முறை"</string>
     <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGBஐப் பயன்படுத்தும்"</string>
@@ -426,7 +453,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம். இதன் மூலம் நீங்கள் விரும்பும்போதெல்லாம்:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;வண்ணங்களை மிகத் தெளிவாகப் பார்க்கலாம்&lt;/li&gt; &lt;li&gt;கவனம் சிதறாமல் இருக்க வண்ணங்களை நீக்கலாம்&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம். இதன் மூலம் நீங்கள் விரும்பும்போதெல்லாம்:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;வண்ணங்களை மிகத் தெளிவாகப் பார்க்கலாம்&lt;/li&gt; &lt;li&gt;&amp;nbsp;கவனம் சிதறாமல் இருக்க வண்ணங்களை நீக்கலாம்&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index 99efbde..67decc9 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -25,7 +25,7 @@
     <item msgid="3288373008277313483">"స్కాన్ చేస్తోంది…"</item>
     <item msgid="6050951078202663628">"కనెక్ట్ చేస్తోంది..."</item>
     <item msgid="8356618438494652335">"ప్రామాణీకరిస్తోంది…"</item>
-    <item msgid="2837871868181677206">"IP చిరునామాను పొందుతోంది…"</item>
+    <item msgid="2837871868181677206">"IP అడ్రస్‌ను పొందుతోంది…"</item>
     <item msgid="4613015005934755724">"కనెక్ట్ చేయబడింది"</item>
     <item msgid="3763530049995655072">"తాత్కాలికంగా రద్దు చేయబడింది"</item>
     <item msgid="7852381437933824454">"డిస్‌కనెక్ట్ చేస్తోంది..."</item>
@@ -39,7 +39,7 @@
     <item msgid="1818677602615822316">"స్కాన్ చేస్తోంది…"</item>
     <item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>కి కనెక్ట్ చేస్తోంది…"</item>
     <item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>తో ప్రామాణీకరిస్తోంది…"</item>
-    <item msgid="4287401332778341890">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> నుండి IP చిరునామాను పొందుతోంది…"</item>
+    <item msgid="4287401332778341890">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> నుండి IP అడ్రస్‌ను పొందుతోంది…"</item>
     <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</item>
     <item msgid="7445993821842009653">"తాత్కాలికంగా రద్దు చేయబడింది"</item>
     <item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> నుండి డిస్‌కనెక్ట్ చేస్తోంది…"</item>
@@ -76,7 +76,7 @@
     <item msgid="1963366694959681026">"avrcp16"</item>
   </string-array>
   <string-array name="bluetooth_map_versions">
-    <item msgid="8786402640610987099">"MAP 1.2 (డిఫాల్ట్)"</item>
+    <item msgid="8786402640610987099">"MAP 1.2 (ఆటోమేటిక్)"</item>
     <item msgid="6817922176194686449">"MAP 1.3"</item>
     <item msgid="3423518690032737851">"MAP 1.4"</item>
   </string-array>
@@ -138,15 +138,15 @@
     <item msgid="1333279807604675720">"స్టీరియో"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="1241278021345116816">"ఆడియో నాణ్యత (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
-    <item msgid="3523665555859696539">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత (660kbps/606kbps)"</item>
-    <item msgid="886408010459747589">"కనెక్షన్ నాణ్యత (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
+    <item msgid="1241278021345116816">"ఆడియో క్వాలిటీ (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
+    <item msgid="3523665555859696539">"సమతుల్య ఆడియో మరియు కనెక్షన్ క్వాలిటీ (660kbps/606kbps)"</item>
+    <item msgid="886408010459747589">"కనెక్షన్ క్వాలిటీ (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
     <item msgid="3808414041654351577">"ఉత్తమ కృషి (అనుకూల బిట్ రేట్)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="804499336721569838">"ఆడియో నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
-    <item msgid="7451422070435297462">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత"</item>
-    <item msgid="6173114545795428901">"కనెక్షన్ నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
+    <item msgid="804499336721569838">"ఆడియో క్వాలిటీ కోసం అనుకూలీకరించబడింది"</item>
+    <item msgid="7451422070435297462">"సమతుల్య ఆడియో మరియు కనెక్షన్ క్వాలిటీ"</item>
+    <item msgid="6173114545795428901">"కనెక్షన్ క్వాలిటీ కోసం అనుకూలీకరించబడింది"</item>
     <item msgid="4349908264188040530">"ఉత్తమ కృషి (అనుకూల బిట్ రేట్)"</item>
   </string-array>
   <string-array name="bluetooth_audio_active_device_summaries">
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 71e4fe2..421a428 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -21,24 +21,51 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"నెట్‌వర్క్‌ల కోసం స్కాన్ చేయడం సాధ్యపడదు"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ఏదీ లేదు"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"పాస్ పాయింట్"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-బిట్"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"సేవ్ చేయబడింది"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"డిస్‌కనెక్ట్ అయ్యింది"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"డిజేబుల్ చేయబడింది"</string>
     <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"IP కాన్ఫిగరేషన్ వైఫల్యం"</string>
-    <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"తక్కువ నాణ్యతా నెట్‌వర్క్ కారణంగా కనెక్ట్ చేయబడలేదు"</string>
+    <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"తక్కువ క్వాలిటీ నెట్‌వర్క్ కారణంగా కనెక్ట్ చేయబడలేదు"</string>
     <string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"WiFi కనెక్షన్ వైఫల్యం"</string>
     <string name="wifi_disabled_password_failure" msgid="6892387079613226738">"ప్రామాణీకరణ సమస్య"</string>
     <string name="wifi_cant_connect" msgid="5718417542623056783">"కనెక్ట్ చేయడం సాధ్యపడదు"</string>
     <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\'కు కనెక్ట్ చేయడం సాధ్యపడదు"</string>
     <string name="wifi_check_password_try_again" msgid="8817789642851605628">"పాస్‌వర్డ్‌ను చెక్ చేసి, మళ్లీ ప్రయత్నించండి"</string>
     <string name="wifi_not_in_range" msgid="1541760821805777772">"పరిధిలో లేదు"</string>
-    <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ఆటోమేటిక్‌గా కనెక్ట్ కాదు"</string>
     <string name="wifi_no_internet" msgid="1774198889176926299">"ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
     <string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
     <string name="connected_to_metered_access_point" msgid="9179693207918156341">"డేటా నియంత్రణ నెట్‌వర్క్‌కు కనెక్ట్ చేయబడింది"</string>
-    <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
-    <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"నెట్‌వర్క్ రేటింగ్ ప్రదాత ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
+    <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ద్వారా ఆటోమేటిక్‌గా కనెక్ట్ చేయబడింది"</string>
+    <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"నెట్‌వర్క్ రేటింగ్ ప్రదాత ద్వారా ఆటోమేటిక్‌గా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="available_via_passpoint" msgid="1716000261192603682">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
@@ -83,14 +110,14 @@
     <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> బ్యాటరీ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ"</string>
     <string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"యాక్టివ్‌గా ఉంది"</string>
     <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"మీడియా ఆడియో"</string>
-    <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ఫోన్ కాల్‌లు"</string>
+    <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ఫోన్ కాల్స్‌"</string>
     <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ఫైల్ బదిలీ"</string>
     <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ఇన్‌పుట్ పరికరం"</string>
     <string name="bluetooth_profile_pan" msgid="1006235139308318188">"ఇంటర్నెట్ యాక్సెస్"</string>
     <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"కాంటాక్ట్ షేరింగ్"</string>
-    <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"పరిచయ భాగస్వామ్యం కోసం ఉపయోగించు"</string>
-    <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ భాగస్వామ్యం"</string>
-    <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన సందేశాలు"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"కాంటాక్ట్ షేరింగ్ కోసం ఉపయోగించండి"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ షేరింగ్"</string>
+    <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన మెసేజ్‌లు"</string>
     <string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM యాక్సెస్"</string>
     <string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
     <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ఆడియో"</string>
@@ -116,7 +143,7 @@
     <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"జత చేయి"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"జత చేయి"</string>
     <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"రద్దు చేయి"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"జత చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ పరిచయాలకు మరియు కాల్ చరిత్రకు ప్రాప్యతను మంజూరు చేస్తుంది."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"పెయిర్ చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ కాంటాక్ట్‌లకు అలాగే కాల్ హిస్టరీకి యాక్సెస్‌ను మంజూరు చేస్తుంది."</string>
     <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో జత చేయడం సాధ్యపడలేదు."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"పిన్ లేదా పాస్‌కీ చెల్లని కారణంగా <xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో పెయిర్ చేయడం సాధ్యపడలేదు."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో కమ్యూనికేట్ చేయడం సాధ్యపడదు."</string>
@@ -153,7 +180,7 @@
     <string name="user_guest" msgid="6939192779649870792">"గెస్ట్"</string>
     <string name="unknown" msgid="3544487229740637809">"తెలియదు"</string>
     <string name="running_process_item_user_label" msgid="3988506293099805796">"యూజర్‌: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
-    <string name="launch_defaults_some" msgid="3631650616557252926">"కొన్ని డిఫాల్ట్‌లు సెట్ చేయబడ్డాయి"</string>
+    <string name="launch_defaults_some" msgid="3631650616557252926">"కొన్ని ఆటోమేటిక్ సెట్టింగ్‌లు సెట్ చేయబడ్డాయి"</string>
     <string name="launch_defaults_none" msgid="8049374306261262709">"ఆటోమేటిక్ ఆప్ష‌న్‌లు ఏవీ సెట్ చేయ‌‌లేదు"</string>
     <string name="tts_settings" msgid="8130616705989351312">"వచనం నుండి ప్రసంగం సెట్టింగ్‌లు"</string>
     <string name="tts_settings_title" msgid="7602210956640483039">"టెక్స్ట్-టు-స్పీచ్ అవుట్‌పుట్"</string>
@@ -172,7 +199,7 @@
     <string name="tts_engine_security_warning" msgid="3372432853837988146">"ఈ ప్రసంగ సమన్వయ ఇంజిన్ చదివి వినిపించబడే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> ఇంజిన్‌లో అందించబడుతుంది. ఈ ప్రసంగ సమన్వయ ఇంజిన్ యొక్క వినియోగాన్ని ప్రారంభించాలా?"</string>
     <string name="tts_engine_network_required" msgid="8722087649733906851">"వచనం నుండి ప్రసంగం అవుట్‌పుట్ కోసం ఈ భాషకు పని చేస్తున్న నెట్‌వర్క్ కనెక్షన్ కావాలి."</string>
     <string name="tts_default_sample_string" msgid="6388016028292967973">"ఇది ప్రసంగ సమన్వయానికి ఉదాహరణ"</string>
-    <string name="tts_status_title" msgid="8190784181389278640">"డిఫాల్ట్ భాష స్థితి"</string>
+    <string name="tts_status_title" msgid="8190784181389278640">"ఆటోమేటిక్ భాష స్టేటస్"</string>
     <string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g>కి పూర్తి మద్దతు ఉంది"</string>
     <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g>కి నెట్‌వర్క్ కనెక్షన్ అవసరం"</string>
     <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g>కు మద్దతు లేదు"</string>
@@ -182,7 +209,7 @@
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"ప్రాధాన్య ఇంజిన్"</string>
     <string name="tts_general_section_title" msgid="8919671529502364567">"సాధారణం"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"ప్రసంగ స్వర స్థాయిని రీసెట్ చేయండి"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"వచనాన్ని చదివి వినిపించే స్వర స్థాయిని డిఫాల్ట్‌కి రీసెట్ చేస్తుంది."</string>
+    <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"టెక్స్ట్‌ను చదివి వినిపించే స్వర స్థాయిని ఆటోమేటిక్‌కు రీసెట్ చేస్తుంది."</string>
   <string-array name="tts_rate_entries">
     <item msgid="9004239613505400644">"చాలా నెమ్మది"</item>
     <item msgid="1815382991399815061">"నెమ్మది"</item>
@@ -199,7 +226,7 @@
     <string name="category_work" msgid="4014193632325996115">"ఆఫీస్"</string>
     <string name="development_settings_title" msgid="140296922921597393">"డెవలపర్ ఆప్షన్‌లు"</string>
     <string name="development_settings_enable" msgid="4285094651288242183">"డెవలపర్ ఎంపికలను ప్రారంభించండి"</string>
-    <string name="development_settings_summary" msgid="8718917813868735095">"అనువర్తన అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
+    <string name="development_settings_summary" msgid="8718917813868735095">"యాప్‌ అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
     <string name="development_settings_not_available" msgid="355070198089140951">"ఈ వినియోగదారు కోసం డెవలపర్ ఎంపికలు అందుబాటులో లేవు"</string>
     <string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN సెట్టింగ్‌లు ఈ వినియోగదారుకి అందుబాటులో లేవు"</string>
     <string name="tethering_settings_not_available" msgid="266821736434699780">"టీథరింగ్ సెట్టింగ్‌లు ఈ వినియోగదారుకి అందుబాటులో లేవు"</string>
@@ -227,12 +254,12 @@
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi పెయిరింగ్ కోడ్"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"పెయిరింగ్ విఫలమైంది"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"పరికరం అదే నెట్‌వర్క్‌కు కనెక్ట్ చేయబడి ఉందని నిర్ధారించుకోండి."</string>
-    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string>
+    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చేయండి"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"పరికరం పెయిర్ చేయబడుతోంది…"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"పరికరాన్ని పెయిర్ చేయడం విఫలమైంది. QR కోడ్ తప్పుగా ఉండడం గాని, లేదా పరికరం అదే నెట్‌వర్క్‌కు కనెక్ట్ అయి లేకపోవడం గాని జరిగింది."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP అడ్రస్ &amp; పోర్ట్"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR కోడ్‌ను స్కాన్ చేయండి"</string>
-    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string>
+    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చేయండి"</string>
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"దయచేసి Wi-Fi నెట్‌వర్క్‌కు కనెక్ట్ చేయండి"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, డీబగ్, dev"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"బగ్ రిపోర్ట్ షార్ట్‌కట్"</string>
@@ -246,8 +273,8 @@
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM అన్‌లాకింగ్‌ను అనుమతించాలా?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"హెచ్చరిక: ఈ సెట్టింగ్ ఆన్ చేయబడినప్పుడు పరికరం రక్షణ లక్షణాలు ఈ పరికరంలో పని చేయవు."</string>
     <string name="mock_location_app" msgid="6269380172542248304">"డమ్మీ లొకేష‌న్‌ యాప్‌ను ఎంచుకోండి"</string>
-    <string name="mock_location_app_not_set" msgid="6972032787262831155">"అనుకృత స్థాన యాప్ ఏదీ సెట్ చేయబడలేదు"</string>
-    <string name="mock_location_app_set" msgid="4706722469342913843">"కృత్రిమ స్థాన యాప్‌: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="mock_location_app_not_set" msgid="6972032787262831155">"డమ్మీ లొకేషన్ యాప్ ఏదీ సెట్ చేయబడలేదు"</string>
+    <string name="mock_location_app_set" msgid="4706722469342913843">"డమ్మీ లొకేషన్ యాప్‌: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"నెట్‌వర్కింగ్"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"వైర్‌లెస్ డిస్‌ప్లే సర్టిఫికేషన్‌"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi విశదీకృత లాగింగ్‌ను ప్రారంభించండి"</string>
@@ -271,8 +298,8 @@
     <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"బ్లూటూత్ ఆడియో కోడెక్‌ని సక్రియం చేయండి\nఎంపిక: ఒక్కో నమూనాలో బిట్‌లు"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"బ్లూటూత్ ఆడియో ఛానెల్ మోడ్"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="2076949781460359589">"బ్లూటూత్ ఆడియో కోడెక్‌ని సక్రియం చేయండి\nఎంపిక: ఛానెల్ మోడ్"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ నాణ్యత"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"బ్లూటూత్ ఆడియో LDAC యాక్టివ్ చేయండి\nకోడెక్ ఎంపిక: ప్లేబ్యాక్ నాణ్యత"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ క్వాలిటీ"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"బ్లూటూత్ ఆడియో LDAC యాక్టివ్ చేయండి\nకోడెక్ ఎంపిక: ప్లేబ్యాక్ క్వాలిటీ"</string>
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"ప్రసారం చేస్తోంది: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
     <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"ప్రైవేట్ DNS"</string>
     <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"ప్రైవేట్ DNS మోడ్‌ను ఎంచుకోండి"</string>
@@ -301,10 +328,10 @@
     <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"ఎల్లప్పుడూ మొబైల్ డేటాను యాక్టివ్‌గా ఉంచు, Wi‑Fi యాక్టివ్‌గా ఉన్నా కూడా (వేగవంతమైన నెట్‌వర్క్ మార్పు కోసం)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"అందుబాటులో ఉంటే టెథెరింగ్ హార్డ్‌వేర్ వేగవృద్ధిని ఉపయోగించండి"</string>
     <string name="adb_warning_title" msgid="7708653449506485728">"USB డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
-    <string name="adb_warning_message" msgid="8145270656419669221">"USB డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్ మరియు మీ పరికరం మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో అనువర్తనాలను ఇన్‌స్టాల్ చేయడానికి మరియు లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
+    <string name="adb_warning_message" msgid="8145270656419669221">"USB డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్ మరియు మీ పరికరం మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్‌లను ఇన్‌స్టాల్ చేయడానికి మరియు లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
     <string name="adbwifi_warning_title" msgid="727104571653031865">"వైర్‌లెస్ డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
     <string name="adbwifi_warning_message" msgid="8005936574322702388">"వైర్‌లెస్ డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్, పరికరాల మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్‌లను ఇన్‌స్టాల్ చేయడానికి, లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
-    <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్‌ల నుండి USB డీబగ్గింగ్‌కు ప్రాప్యతను ఉపసంహరించాలా?"</string>
+    <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్‌ల నుండి USB డీబగ్గింగ్‌కు యాక్సెస్‌ను ఉపసంహరించాలా?"</string>
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"అభివృద్ధి సెట్టింగ్‌లను అనుమతించాలా?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"ఈ సెట్టింగ్‌లు అభివృద్ధి వినియోగం కోసం మాత్రమే ఉద్దేశించబడినవి. వీటి వలన మీ పరికరం మరియు దీనిలోని యాప్‌లు విచ్ఛిన్నం కావచ్చు లేదా తప్పుగా ప్రవర్తించవచ్చు."</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ద్వారా యాప్‌లను వెరిఫై చేయి"</string>
@@ -314,7 +341,7 @@
     <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"బ్లూటూత్ Gabeldorsche ఫీచర్ స్ట్యాక్‌ను ఎనేబుల్ చేస్తుంది."</string>
     <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"మెరుగైన కనెక్టివిటీ ఫీచర్‌ను ఎనేబుల్ చేస్తుంది."</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"స్థానిక టెర్మినల్"</string>
-    <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ ప్రాప్యతను అందించే టెర్మినల్ యాప్‌ను ప్రారంభించు"</string>
+    <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్‌ను అందించే టెర్మినల్ యాప్‌ను ప్రారంభించు"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP చెకింగ్‌"</string>
     <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP తనిఖీ ప్రవర్తనను సెట్ చేయండి"</string>
     <string name="debug_debugging_category" msgid="535341063709248842">"డీబగ్గింగ్"</string>
@@ -383,12 +410,12 @@
     <string name="local_backup_password_title" msgid="4631017948933578709">"డెస్క్‌టాప్ బ్యాకప్ పాస్‌వర్డ్"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌లు ప్రస్తుతం రక్షించబడలేదు"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
-    <string name="local_backup_password_toast_success" msgid="4891666204428091604">"కొత్త బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేసారు"</string>
+    <string name="local_backup_password_toast_success" msgid="4891666204428091604">"కొత్త బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేశారు"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="2994718182129097733">"కొత్త పాస్‌వర్డ్ మరియు నిర్ధారణ సరిపోలడం లేదు"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="714669442363647122">"బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేయడంలో వైఫల్యం"</string>
     <string name="loading_injected_setting_summary" msgid="8394446285689070348">"లోడ్ చేస్తోంది…"</string>
   <string-array name="color_mode_names">
-    <item msgid="3836559907767149216">"సచేతనం (డిఫాల్ట్)"</item>
+    <item msgid="3836559907767149216">"వైబ్రంట్ (ఆటోమేటిక్)"</item>
     <item msgid="9112200311983078311">"సహజం"</item>
     <item msgid="6564241960833766170">"స్టాండర్డ్"</item>
   </string-array>
@@ -408,7 +435,7 @@
     <string name="transcode_notification" msgid="5560515979793436168">"ట్రాన్స్‌కోడింగ్ నోటిఫికేషన్‌లను చూపండి"</string>
     <string name="transcode_disable_cache" msgid="3160069309377467045">"ట్రాన్స్‌కోడింగ్ కాష్‌ను డిజేబుల్ చేయండి"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సర్వీస్‌లు"</string>
-    <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్‌లను వీక్షించండి, కంట్రోల్‌ చేయండి"</string>
+    <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్‌లను చూడండి, కంట్రోల్‌ చేయండి"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ప్రయత్నించండి."</string>
@@ -489,7 +516,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>
@@ -529,7 +556,7 @@
     <string name="help_label" msgid="3528360748637781274">"సహాయం &amp; ఫీడ్‌బ్యాక్"</string>
     <string name="storage_category" msgid="2287342585424631813">"స్టోరేజ్"</string>
     <string name="shared_data_title" msgid="1017034836800864953">"షేర్ చేసిన డేటా"</string>
-    <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, సవరించండి"</string>
+    <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, ఎడిట్ చేయండి"</string>
     <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ఈ యూజర్ కోసం షేర్ చేసిన డేటా ఏదీ లేదు."</string>
     <string name="shared_data_query_failure_text" msgid="3489828881998773687">"షేర్ చేసిన డేటా పొందడంలో ఎర్రర్ ఏర్పడింది. మళ్లీ ట్రై చేయండి."</string>
     <string name="blob_id_text" msgid="8680078988996308061">"షేర్ చేసిన డేటా ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
@@ -541,8 +568,8 @@
     <string name="accessor_expires_text" msgid="4625619273236786252">"లీజు గడువు <xliff:g id="DATE">%s</xliff:g>తో ముగుస్తుంది"</string>
     <string name="delete_blob_text" msgid="2819192607255625697">"షేర్ చేసిన డేటాను తొలగించు"</string>
     <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"మీరు ఖచ్చితంగా ఈ షేర్ చేసిన డేటాను తొలగించాలనుకుంటున్నారా?"</string>
-    <string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత అనువర్తనాలను మరియు కంటెంట్‌ను కలిగి ఉన్నారు"</string>
-    <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి అనువర్తనాలకు మరియు కంటెంట్‌కు ప్రాప్యతను పరిమితం చేయవచ్చు"</string>
+    <string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత యాప్‌లను మరియు కంటెంట్‌ను కలిగి ఉన్నారు"</string>
+    <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి యాప్‌లకు మరియు కంటెంట్‌కు యాక్సెస్‌ను పరిమితం చేయవచ్చు"</string>
     <string name="user_add_user_item_title" msgid="2394272381086965029">"యూజర్"</string>
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"కొత్త వినియోగదారుని జోడించాలా?"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 494a690..51a0420 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ไม่สามารถสแกนหาเครือข่าย"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"ไม่มี/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"ไม่มี"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"ไม่มี/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 บิต"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"บันทึกแล้ว"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"ยกเลิกการเชื่อมต่อแล้ว"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"ปิดอยู่"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a6f93c5..1bc84af 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Hindi makapag-scan ng mga network"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Wala/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Wala"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Wala/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Na-save"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Nadiskonekta"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Naka-disable"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index e1d9831..a00457a 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Ağlar taranamıyor"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Yok"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Kaydedildi"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Bağlı değil"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Devre dışı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 5b96e27..6aac2932 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Неможливо здійснити сканування мереж"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Немає/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Немає"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Немає/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise, 192-бітне шифрування"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Збережено"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Від’єднано"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Вимкнено"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index af60e9d..14cea9a 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"نیٹ ورکس کیلئے اسکین نہيں کر سکتے ہیں"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"کوئی نہیں"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"‏WPA ذاتی"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"‏WPA2 ذاتی"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"‏WPA/WPA2 ذاتی"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"‏WPA/WPA2/WPA3 انٹرپرائز"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"‏WPA انٹرپرائز"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"‏WPA/WPA2 انٹرپرائز"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"‏WPA2/WPA3 انٹرپرائز"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"‏WPA3 انٹرپرائز"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"پاس پوائنٹ"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"‏WPA3 ذاتی"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"‏WPA2/WPA3 ذاتی"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"‏WPA3 انٹرپرائز 192 بِٹ"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"محفوظ کردیا گیا"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"غیر منسلک"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"غیر فعال"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 53f8520..47c828d 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Tarmoqlarni tekshirib chiqishni iloji bo‘lmadi"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Sozlanmagan/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Hech qanday"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Sozlanmagan/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Saqlangan"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Ulanmagan"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Yoqilmagan"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index bf4ab28..aaaaada 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Không thể dò tìm mạng"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Không/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Không"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Không/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Đã lưu"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Đã ngắt kết nối"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Đã tắt"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index aac8eed..c85dba0 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"无法扫描网络"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"无/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"无"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"无/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 位"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"已保存"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"已断开连接"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 78b57cc..dccd1df 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"無法掃瞄網絡"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"None/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"無"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"None/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 位元"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"已儲存"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"已中斷連線"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 637714a..afa27aa 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"無法掃描網路"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"無/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"無"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"無/Enhanced Open"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192 位元"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"已儲存"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"已中斷連線"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index ae262fc..9b3063d 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -21,7 +21,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Ayikwazi ukuhlola amanethiwekhi"</string>
+    <string name="wifi_security_short_wep" msgid="7939809393561636237">"I-WEP"</string>
+    <string name="wifi_security_short_wpa" msgid="6998160832497442533">"I-WPA"</string>
+    <string name="wifi_security_short_wpa2" msgid="7697856994856831026">"I-WPA2"</string>
+    <string name="wifi_security_short_wpa_wpa2" msgid="2399839645955520093">"I-WPA/WPA2"</string>
+    <string name="wifi_security_short_eap" msgid="5029688687205212985">"802.1x"</string>
+    <string name="wifi_security_short_eap_wpa" msgid="8510772177310043426">"I-WPA-EAP"</string>
+    <string name="wifi_security_short_eap_wpa2_wpa3" msgid="6455656470422244501">"I-RSN-EAP"</string>
+    <string name="wifi_security_short_sae" msgid="78353562671556266">"I-WPA3"</string>
+    <string name="wifi_security_short_psk_sae" msgid="4965830739185952958">"I-WPA2/WPA3"</string>
+    <string name="wifi_security_short_none_owe" msgid="8827409046261759703">"Akukho/OWE"</string>
+    <string name="wifi_security_short_owe" msgid="5073524307942025369">"I-OWE"</string>
+    <string name="wifi_security_short_eap_suiteb" msgid="4174071135081556115">"I-Suite-B-192"</string>
     <string name="wifi_security_none" msgid="7392696451280611452">"Lutho"</string>
+    <string name="wifi_security_wep" msgid="1413627788581122366">"I-WEP"</string>
+    <string name="wifi_security_wpa" msgid="1072450904799930636">"I-WPA-Personal"</string>
+    <string name="wifi_security_wpa2" msgid="4038267581230425543">"I-WPA2-Personal"</string>
+    <string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"I-WPA/WPA2-Personal"</string>
+    <string name="wifi_security_eap" msgid="6179633834446852269">"I-WPA/WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa" msgid="6189023812330549957">"I-WPA-Enterprise"</string>
+    <string name="wifi_security_eap_wpa_wpa2" msgid="1089879674896108216">"I-WPA/WPA2-Enterprise"</string>
+    <string name="wifi_security_eap_wpa2_wpa3" msgid="2952912020876252266">"I-WPA2/WPA3-Enterprise"</string>
+    <string name="wifi_security_eap_wpa3" msgid="7961135182909018796">"I-WPA3-Enterprise"</string>
+    <string name="wifi_security_passpoint" msgid="2209078477216565387">"I-Passpoint"</string>
+    <string name="wifi_security_sae" msgid="3644520541721422843">"I-WPA3-Personal"</string>
+    <string name="wifi_security_psk_sae" msgid="8135104122179904684">"I-WPA2/WPA3-Personal"</string>
+    <string name="wifi_security_none_owe" msgid="5241745828327404101">"Akukho/Ukuthuthukisa Kuvuliwe"</string>
+    <string name="wifi_security_owe" msgid="3343421403561657809">"Ukuthuthukisa Kuvuliwe"</string>
+    <string name="wifi_security_eap_suiteb" msgid="415842785991698142">"I-WPA3-Enterprise 192-bit"</string>
     <string name="wifi_remembered" msgid="3266709779723179188">"Kulondoloziwe"</string>
     <string name="wifi_disconnected" msgid="7054450256284661757">"Inqamukile"</string>
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Akusebenzi"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 183a06c..cab7cee 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -20,68 +20,68 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Toast message when Wi-Fi cannot scan for networks -->
     <string name="wifi_fail_to_scan">Can\'t scan for networks</string>
-    <!-- Concise terminology for wifi with WEP security -->
-    <string name="wifi_security_short_wep" translatable="false">WEP</string>
-    <!-- Concise terminology for wifi with WPA security -->
-    <string name="wifi_security_short_wpa" translatable="false">WPA</string>
-    <!-- Concise terminology for wifi with WPA2 security -->
-    <string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
-    <!-- Concise terminology for wifi with both WPA/WPA2 security -->
-    <string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
+    <!-- Concise terminology for wifi with WEP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_wep">WEP</string>
+    <!-- Concise terminology for wifi with WPA security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_wpa">WPA</string>
+    <!-- Concise terminology for wifi with WPA2 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_wpa2">WPA2</string>
+    <!-- Concise terminology for wifi with both WPA/WPA2 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
     <!-- Concise terminology for wifi with unknown PSK type -->
     <string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
-    <!-- Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_short_eap" translatable="false">802.1x</string>
-    <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
-    <string name="wifi_security_short_eap_wpa" translatable="false">WPA-EAP</string>
-    <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
-    <string name="wifi_security_short_eap_wpa2_wpa3" translatable="false">RSN-EAP</string>
-    <!-- Concise terminology for wifi with WPA3 security -->
-    <string name="wifi_security_short_sae" translatable="false">WPA3</string>
-    <!-- Concise terminology for wifi with WPA2/WPA3 transition security -->
-    <string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string>
-    <!-- Concise terminology for Wi-Fi with None/OWE transition mode security -->
-    <string name="wifi_security_short_none_owe" translatable="false">None/OWE</string>
-    <!-- Concise terminology for wifi with OWE security -->
-    <string name="wifi_security_short_owe" translatable="false">OWE</string>
-    <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
-    <string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B-192</string>
+    <!-- Concise terminology for wifi with 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_eap">802.1x</string>
+    <!-- Concise terminology for wifi with WPA 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_eap_wpa">WPA-EAP</string>
+    <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_eap_wpa2_wpa3">RSN-EAP</string>
+    <!-- Concise terminology for wifi with WPA3 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_sae">WPA3</string>
+    <!-- Concise terminology for wifi with WPA2/WPA3 transition security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_psk_sae">WPA2/WPA3</string>
+    <!-- Concise terminology for Wi-Fi with None/OWE transition mode security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_none_owe">None/OWE</string>
+    <!-- Concise terminology for wifi with OWE security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_owe">OWE</string>
+    <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_short_eap_suiteb">Suite-B-192</string>
 
     <!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. [CHAR LIMIT=40] -->
     <string name="wifi_security_none">None</string>
 
-    <!-- Terminology for wifi with WEP security -->
-    <string name="wifi_security_wep" translatable="false">WEP</string>
-    <!-- Terminology for wifi with WPA security -->
-    <string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
-    <!-- Terminology for wifi with WPA2 security -->
-    <string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
-    <!-- Terminology for wifi with both WPA/WPA2 security, or unknown -->
-    <string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
+    <!-- Terminology for wifi with WEP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_wep">WEP</string>
+    <!-- Terminology for wifi with WPA security [CHAR LIMIT=40] -->
+    <string name="wifi_security_wpa">WPA-Personal</string>
+    <!-- Terminology for wifi with WPA2 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_wpa2">WPA2-Personal</string>
+    <!-- Terminology for wifi with both WPA/WPA2 security, or unknown [CHAR LIMIT=40] -->
+    <string name="wifi_security_wpa_wpa2">WPA/WPA2-Personal</string>
     <!-- Terminology for wifi with unknown PSK type -->
     <string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
-    <!-- Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_eap" translatable="false">WPA/WPA2/WPA3-Enterprise</string>
-    <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
-    <string name="wifi_security_eap_wpa" translatable="false">WPA-Enterprise</string>
-    <!-- Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_eap_wpa_wpa2" translatable="false">WPA/WPA2-Enterprise</string>
-    <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
-    <string name="wifi_security_eap_wpa2_wpa3" translatable="false">WPA2/WPA3-Enterprise</string>
-    <!-- Concise terminology for wifi with WPA3 802.1x EAP security -->
-    <string name="wifi_security_eap_wpa3" translatable="false">WPA3-Enterprise</string>
-    <!-- Concise terminology for Passpoint network -->
-    <string name="wifi_security_passpoint" translatable="false">Passpoint</string>
-    <!-- Terminology for wifi with WPA3 security -->
-    <string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
-    <!-- Terminology for wifi with WPA2/WPA3 Transition mode security -->
-    <string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string>
-    <!-- Terminology for Wi-Fi with None/OWE transition mode security -->
-    <string name="wifi_security_none_owe" translatable="false">None/Enhanced Open</string>
-    <!-- Terminology for wifi with OWE security -->
-    <string name="wifi_security_owe" translatable="false">Enhanced Open</string>
-    <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
-    <string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise 192-bit</string>
+    <!-- Concise terminology for wifi with 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_eap">WPA/WPA2/WPA3-Enterprise</string>
+    <!-- Concise terminology for wifi with WPA 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_eap_wpa">WPA-Enterprise</string>
+    <!-- Concise terminology for wifi with 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_eap_wpa_wpa2">WPA/WPA2-Enterprise</string>
+    <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_eap_wpa2_wpa3">WPA2/WPA3-Enterprise</string>
+    <!-- Concise terminology for wifi with WPA3 802.1x EAP security [CHAR LIMIT=40] -->
+    <string name="wifi_security_eap_wpa3">WPA3-Enterprise</string>
+    <!-- Concise terminology for Passpoint network [CHAR LIMIT=40] -->
+    <string name="wifi_security_passpoint">Passpoint</string>
+    <!-- Terminology for wifi with WPA3 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_sae">WPA3-Personal</string>
+    <!-- Terminology for wifi with WPA2/WPA3 Transition mode security [CHAR LIMIT=40] -->
+    <string name="wifi_security_psk_sae">WPA2/WPA3-Personal</string>
+    <!-- Terminology for Wi-Fi with None/OWE transition mode security [CHAR LIMIT=40] -->
+    <string name="wifi_security_none_owe">None/Enhanced Open</string>
+    <!-- Terminology for wifi with OWE security [CHAR LIMIT=40] -->
+    <string name="wifi_security_owe">Enhanced Open</string>
+    <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security [CHAR LIMIT=40] -->
+    <string name="wifi_security_eap_suiteb">WPA3-Enterprise 192-bit</string>
 
     <!-- Summary for the remembered network. -->
     <string name="wifi_remembered">Saved</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
new file mode 100644
index 0000000..246fc8dd
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
@@ -0,0 +1,160 @@
+/*
+ * 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.settingslib;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Switch;
+
+import androidx.annotation.Keep;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * A custom preference that provides inline switch toggle. It has a mandatory field for title, and
+ * optional fields for icon and sub-text. And it can be restricted by admin state.
+ */
+public class PrimarySwitchPreference extends RestrictedPreference {
+
+    private Switch mSwitch;
+    private boolean mChecked;
+    private boolean mCheckedSet;
+    private boolean mEnableSwitch = true;
+
+    public PrimarySwitchPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public PrimarySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public PrimarySwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public PrimarySwitchPreference(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected int getSecondTargetResId() {
+        return R.layout.restricted_preference_widget_primary_switch;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        final View switchWidget = holder.findViewById(R.id.switchWidget);
+        if (switchWidget != null) {
+            switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
+            switchWidget.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (mSwitch != null && !mSwitch.isEnabled()) {
+                        return;
+                    }
+                    setChecked(!mChecked);
+                    if (!callChangeListener(mChecked)) {
+                        setChecked(!mChecked);
+                    } else {
+                        persistBoolean(mChecked);
+                    }
+                }
+            });
+
+            // Consumes move events to ignore drag actions.
+            switchWidget.setOnTouchListener((v, event) -> {
+                return event.getActionMasked() == MotionEvent.ACTION_MOVE;
+            });
+        }
+
+        mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
+        if (mSwitch != null) {
+            mSwitch.setContentDescription(getTitle());
+            mSwitch.setChecked(mChecked);
+            mSwitch.setEnabled(mEnableSwitch);
+        }
+    }
+
+    public boolean isChecked() {
+        return mSwitch != null && mChecked;
+    }
+
+    /**
+     * Used to validate the state of mChecked and mCheckedSet when testing, without requiring
+     * that a ViewHolder be bound to the object.
+     */
+    @Keep
+    @Nullable
+    public Boolean getCheckedState() {
+        return mCheckedSet ? mChecked : null;
+    }
+
+    /**
+     * Set the checked status to be {@code checked}.
+     *
+     * @param checked The new checked status
+     */
+    public void setChecked(boolean checked) {
+        // Always set checked the first time; don't assume the field's default of false.
+        final boolean changed = mChecked != checked;
+        if (changed || !mCheckedSet) {
+            mChecked = checked;
+            mCheckedSet = true;
+            if (mSwitch != null) {
+                mSwitch.setChecked(checked);
+            }
+        }
+    }
+
+    /**
+     * Set the Switch to be the status of {@code enabled}.
+     *
+     * @param enabled The new enabled status
+     */
+    public void setSwitchEnabled(boolean enabled) {
+        mEnableSwitch = enabled;
+        if (mSwitch != null) {
+            mSwitch.setEnabled(enabled);
+        }
+    }
+
+    /**
+     * If admin is not null, disables the switch.
+     * Otherwise, keep it enabled.
+     */
+    public void setDisabledByAdmin(EnforcedAdmin admin) {
+        super.setDisabledByAdmin(admin);
+        setSwitchEnabled(admin == null);
+    }
+
+    public Switch getSwitch() {
+        return mSwitch;
+    }
+
+    @Override
+    protected boolean shouldHideSecondTarget() {
+        return getSecondTargetResId() == 0;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
similarity index 76%
rename from packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
rename to packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
index 877dd2d..2e7cfcb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.location;
+package com.android.settingslib.applications;
+
 
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -39,14 +40,24 @@
 import java.util.List;
 
 /**
- * Retrieves the information of applications which accessed location recently.
+ * Retrieval of app ops information for the specified ops.
  */
-public class RecentLocationAccesses {
-    private static final String TAG = RecentLocationAccesses.class.getSimpleName();
+public class RecentAppOpsAccess {
     @VisibleForTesting
-    static final String ANDROID_SYSTEM_PACKAGE_NAME = "android";
+    static final int[] LOCATION_OPS = new int[]{
+            AppOpsManager.OP_FINE_LOCATION,
+            AppOpsManager.OP_COARSE_LOCATION,
+    };
+    private static final int[] MICROPHONE_OPS = new int[]{
+            AppOpsManager.OP_RECORD_AUDIO,
+    };
 
-    // Keep last 24 hours of location app information.
+
+    private static final String TAG = RecentAppOpsAccess.class.getSimpleName();
+    @VisibleForTesting
+    public static final String ANDROID_SYSTEM_PACKAGE_NAME = "android";
+
+    // Keep last 24 hours of access app information.
     private static final long RECENT_TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
 
     /** The flags for querying ops that are trusted for showing in the UI. */
@@ -54,47 +65,55 @@
             | AppOpsManager.OP_FLAG_UNTRUSTED_PROXY
             | AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
 
-    @VisibleForTesting
-    static final int[] LOCATION_OPS = new int[]{
-            AppOpsManager.OP_FINE_LOCATION,
-            AppOpsManager.OP_COARSE_LOCATION,
-    };
-
     private final PackageManager mPackageManager;
     private final Context mContext;
+    private final int[] mOps;
     private final IconDrawableFactory mDrawableFactory;
     private final Clock mClock;
 
-    public RecentLocationAccesses(Context context) {
-        this(context, Clock.systemDefaultZone());
+    public RecentAppOpsAccess(Context context, int[] ops) {
+        this(context, Clock.systemDefaultZone(), ops);
     }
 
     @VisibleForTesting
-    RecentLocationAccesses(Context context, Clock clock) {
+    RecentAppOpsAccess(Context context, Clock clock, int[] ops) {
         mContext = context;
         mPackageManager = context.getPackageManager();
+        mOps = ops;
         mDrawableFactory = IconDrawableFactory.newInstance(context);
         mClock = clock;
     }
 
     /**
-     * Fills a list of applications which queried location recently within specified time.
-     * Apps are sorted by recency. Apps with more recent location accesses are in the front.
+     * Creates an instance of {@link RecentAppOpsAccess} for location (coarse and fine) access.
+     */
+    public static RecentAppOpsAccess createForLocation(Context context) {
+        return new RecentAppOpsAccess(context, LOCATION_OPS);
+    }
+
+    /**
+     * Creates an instance of {@link RecentAppOpsAccess} for microphone access.
+     */
+    public static RecentAppOpsAccess createForMicrophone(Context context) {
+        return new RecentAppOpsAccess(context, MICROPHONE_OPS);
+    }
+
+    /**
+     * Fills a list of applications which queried for access recently within specified time.
+     * Apps are sorted by recency. Apps with more recent accesses are in the front.
      */
     @VisibleForTesting
-    List<Access> getAppList(boolean showSystemApps) {
-        // Retrieve a location usage list from AppOps
-        PackageManager pm = mContext.getPackageManager();
-        AppOpsManager aoManager =
-                (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-        List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps(LOCATION_OPS);
+    public List<Access> getAppList(boolean showSystemApps) {
+        // Retrieve a access usage list from AppOps
+        AppOpsManager aoManager = mContext.getSystemService(AppOpsManager.class);
+        List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps(mOps);
 
         final int appOpsCount = appOps != null ? appOps.size() : 0;
 
         // Process the AppOps list and generate a preference list.
         ArrayList<Access> accesses = new ArrayList<>(appOpsCount);
         final long now = mClock.millis();
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        final UserManager um = mContext.getSystemService(UserManager.class);
         final List<UserHandle> profiles = um.getUserProfiles();
 
         for (int i = 0; i < appOpsCount; ++i) {
@@ -111,9 +130,10 @@
             // Don't show apps that do not have user sensitive location permissions
             boolean showApp = true;
             if (!showSystemApps) {
-                for (int op : LOCATION_OPS) {
+                for (int op : mOps) {
                     final String permission = AppOpsManager.opToPermission(op);
-                    final int permissionFlags = pm.getPermissionFlags(permission, packageName,
+                    final int permissionFlags = mPackageManager.getPermissionFlags(permission,
+                            packageName,
                             user);
                     if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
                             PermissionChecker.PID_UNKNOWN, uid, packageName)
@@ -144,12 +164,11 @@
         return accesses;
     }
 
-
     /**
-     * Gets a list of apps that accessed location recently, sorting by recency.
+     * Gets a list of apps that accessed the app op recently, sorting by recency.
      *
      * @param showSystemApps whether includes system apps in the list.
-     * @return the list of apps that recently accessed location.
+     * @return the list of apps that recently accessed the app op.
      */
     public List<Access> getAppListSorted(boolean showSystemApps) {
         List<Access> accesses = getAppList(showSystemApps);
@@ -174,18 +193,18 @@
             AppOpsManager.PackageOps ops) {
         String packageName = ops.getPackageName();
         List<AppOpsManager.OpEntry> entries = ops.getOps();
-        long locationAccessFinishTime = 0L;
-        // Earliest time for a location access to end and still be shown in list.
-        long recentLocationCutoffTime = now - RECENT_TIME_INTERVAL_MILLIS;
+        long accessFinishTime = 0L;
+        // Earliest time for a access to end and still be shown in list.
+        long recentAccessCutoffTime = now - RECENT_TIME_INTERVAL_MILLIS;
         // Compute the most recent access time from all op entries.
         for (AppOpsManager.OpEntry entry : entries) {
             long lastAccessTime = entry.getLastAccessTime(TRUSTED_STATE_FLAGS);
-            if (lastAccessTime > locationAccessFinishTime) {
-                locationAccessFinishTime = lastAccessTime;
+            if (lastAccessTime > accessFinishTime) {
+                accessFinishTime = lastAccessTime;
             }
         }
         // Bail out if the entry is out of date.
-        if (locationAccessFinishTime < recentLocationCutoffTime) {
+        if (accessFinishTime < recentAccessCutoffTime) {
             return null;
         }
 
@@ -213,13 +232,16 @@
                 badgedAppLabel = null;
             }
             access = new Access(packageName, userHandle, icon, appLabel, badgedAppLabel,
-                    locationAccessFinishTime);
+                    accessFinishTime);
         } catch (NameNotFoundException e) {
             Log.w(TAG, "package name not found for " + packageName + ", userId " + userId);
         }
         return access;
     }
 
+    /**
+     * Information about when an app last accessed a particular app op.
+     */
     public static class Access {
         public final String packageName;
         public final UserHandle userHandle;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 63cb381..c47ce41 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -101,6 +101,7 @@
     private PbapServerProfile mPbapProfile;
     private HearingAidProfile mHearingAidProfile;
     private SapProfile mSapProfile;
+    private VolumeControlProfile mVolumeControlProfile;
 
     /**
      * Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -220,6 +221,16 @@
             mSapProfile = new SapProfile(mContext, mDeviceManager, this);
             addProfile(mSapProfile, SapProfile.NAME, BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
         }
+        if (mVolumeControlProfile == null
+                && supportedList.contains(BluetoothProfile.VOLUME_CONTROL)) {
+            if (DEBUG) {
+                Log.d(TAG, "Adding local Volume Control profile");
+            }
+            mVolumeControlProfile = new VolumeControlProfile();
+            // Note: no event handler for VCP, only for being connectable.
+            mProfileNameMap.put(VolumeControlProfile.NAME, mVolumeControlProfile);
+        }
+
         mEventManager.registerProfileIntentReceiver();
     }
 
@@ -569,6 +580,12 @@
             removedProfiles.remove(mSapProfile);
         }
 
+        if (mVolumeControlProfile != null
+                && ArrayUtils.contains(uuids, BluetoothUuid.VOLUME_CONTROL)) {
+            profiles.add(mVolumeControlProfile);
+            removedProfiles.remove(mVolumeControlProfile);
+        }
+
         if (DEBUG) {
             Log.d(TAG,"New Profiles" + profiles.toString());
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
new file mode 100644
index 0000000..511df28
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
@@ -0,0 +1,96 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+
+/**
+ * VolumeControlProfile handles Bluetooth Volume Control Controller role
+ */
+public class VolumeControlProfile implements LocalBluetoothProfile {
+    private static final String TAG = "VolumeControlProfile";
+    static final String NAME = "VCP";
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 23;
+
+    @Override
+    public boolean accessProfileEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    @Override
+    public int getConnectionStatus(BluetoothDevice device) {
+        return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle VCP
+    }
+
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
+        return false;
+    }
+
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle VCP
+    }
+
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        return false;
+    }
+
+    @Override
+    public boolean isProfileReady() {
+        return true;
+    }
+
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.VOLUME_CONTROL;
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    @Override
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    @Override
+    public int getNameResource(BluetoothDevice device) {
+        return 0; // VCP profile not displayed in UI
+    }
+
+    @Override
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return 0;   // VCP profile not displayed in UI
+    }
+
+    @Override
+    public int getDrawableResource(BluetoothClass btClass) {
+        // no icon for VCP
+        return 0;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
index 364698f..2c0162f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
@@ -68,7 +68,6 @@
             Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);
             final Intent intent = new Intent(ACTION_LEARN_MORE)
                     .putExtra(EXTRA_SETTING_KEY, EXTRA_SETTING_VALUE)
-                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                     .setPackage(enforcedAdmin.component.getPackageName());
             context.startActivity(intent);
         };
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 79446e4..3c43f4a6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -15,7 +15,6 @@
  */
 package com.android.settingslib.media;
 
-import static android.media.MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK;
 import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
 import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
 import static android.media.MediaRoute2Info.TYPE_DOCK;
@@ -44,6 +43,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 +57,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 +147,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,65 +376,18 @@
     }
 
     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)
     boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
-        if (sessionInfo == null) {
-            Log.w(TAG, "shouldEnableVolumeSeekBar() package name is null or empty!");
-            return false;
-        }
-        final List<MediaRoute2Info> mediaRoute2Infos =
-                mRouterManager.getSelectedRoutes(sessionInfo);
-        // More than one selected route
-        if (mediaRoute2Infos.size() > 1) {
-            if (DEBUG) {
-                Log.d(TAG, "shouldEnableVolumeSeekBar() package name : "
-                        + sessionInfo.getClientPackageName()
-                        + ", mediaRoute2Infos.size() " + mediaRoute2Infos.size());
-            }
-            return false;
-        }
-        // Route contains group feature
-        for (MediaRoute2Info mediaRoute2Info : mediaRoute2Infos) {
-            final List<String> features = mediaRoute2Info.getFeatures();
-            if (features.contains(FEATURE_REMOTE_GROUP_PLAYBACK)) {
-                if (DEBUG) {
-                    Log.d(TAG, "shouldEnableVolumeSeekBar() package name : "
-                            + mediaRoute2Info.getClientPackageName()
-                            + "contain group playback ");
-                }
-                return false;
-            }
-        }
-        return true;
+        return false;
     }
 
     private void refreshDevices() {
@@ -456,7 +418,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 +427,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/src/com/android/settingslib/users/AppCopyHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppCopyHelper.java
new file mode 100644
index 0000000..75e23e0
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppCopyHelper.java
@@ -0,0 +1,276 @@
+/*
+ * 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.settingslib.users;
+
+import android.app.AppGlobals;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper for {@link com.android.settings.users.AppCopyFragment}, for keeping track of which
+ * packages a user has chosen to copy to a second user and fulfilling that installation.
+ *
+ * To test, use
+ *   atest SettingsLibTests:com.android.settingslib.users.AppCopyingHelperTest
+ */
+public class AppCopyHelper {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "AppCopyHelper";
+
+    private final PackageManager mPackageManager;
+    private final IPackageManager mIPm;
+    private final UserHandle mUser;
+    private boolean mLeanback;
+
+    /** Set of packages to be installed. */
+    private final ArraySet<String> mSelectedPackages = new ArraySet<>();
+    /** List of installable packages from which the user can choose. */
+    private List<SelectableAppInfo> mVisibleApps;
+
+    public AppCopyHelper(Context context, UserHandle user) {
+        this(new Injector(context, user));
+    }
+
+    @VisibleForTesting
+    AppCopyHelper(Injector injector) {
+        mPackageManager = injector.getPackageManager();
+        mIPm = injector.getIPackageManager();
+        mUser = injector.getUser();
+    }
+
+    /** Toggles whether the package has been selected. */
+    public void setPackageSelected(String packageName, boolean selected) {
+        if (selected) {
+            mSelectedPackages.add(packageName);
+        } else {
+            mSelectedPackages.remove(packageName);
+        }
+    }
+
+    /** Resets all packages as unselected. */
+    public void resetSelectedPackages() {
+        mSelectedPackages.clear();
+    }
+
+    public void setLeanback(boolean isLeanback) {
+        mLeanback = isLeanback;
+    }
+
+    /** List of installable packages from which the user can choose. */
+    public List<SelectableAppInfo> getVisibleApps() {
+        return mVisibleApps;
+    }
+
+    /** Installs the packages that have been selected using {@link #setPackageSelected} */
+    public void installSelectedApps() {
+        for (int i = 0; i < mSelectedPackages.size(); i++) {
+            final String packageName = mSelectedPackages.valueAt(i);
+            installSelectedApp(packageName);
+        }
+    }
+
+    private void installSelectedApp(String packageName) {
+        final int userId = mUser.getIdentifier();
+        try {
+            final ApplicationInfo info = mIPm.getApplicationInfo(packageName,
+                    PackageManager.MATCH_ANY_USER, userId);
+            if (info == null || !info.enabled
+                    || (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
+                Log.i(TAG, "Installing " + packageName);
+                mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier(),
+                        PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+                        PackageManager.INSTALL_REASON_UNKNOWN, null);
+            }
+            if (info != null && (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN) != 0
+                    && (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
+                Log.i(TAG, "Unhiding " + packageName);
+                mIPm.setApplicationHiddenSettingAsUser(packageName, false, userId);
+            }
+        } catch (RemoteException re) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Fetches the list of installable packages to display.
+     * This list can be obtained from {@link #getVisibleApps}.
+     */
+    public void fetchAndMergeApps() {
+        mVisibleApps = new ArrayList<>();
+        addCurrentUsersApps();
+        removeSecondUsersApp();
+    }
+
+    /**
+     * Adds to {@link #mVisibleApps} packages from the current user:
+     *  (1) All downloaded apps and
+     *  (2) all system apps that have launcher or widgets.
+     */
+    private void addCurrentUsersApps() {
+        // Add system package launchers of the current user
+        final Intent launcherIntent = new Intent(Intent.ACTION_MAIN).addCategory(
+                mLeanback ? Intent.CATEGORY_LEANBACK_LAUNCHER : Intent.CATEGORY_LAUNCHER);
+        addSystemApps(mVisibleApps, launcherIntent);
+
+        // Add system package widgets of the current user
+        final Intent widgetIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        addSystemApps(mVisibleApps, widgetIntent);
+
+        // Add all downloaded apps of the current user
+        final List<ApplicationInfo> installedApps = mPackageManager.getInstalledApplications(0);
+        for (ApplicationInfo app : installedApps) {
+            // If it's not installed, skip
+            if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
+
+            if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
+                // Downloaded app
+                final SelectableAppInfo info = new SelectableAppInfo();
+                info.packageName = app.packageName;
+                info.appName = app.loadLabel(mPackageManager);
+                info.icon = app.loadIcon(mPackageManager);
+                mVisibleApps.add(info);
+            }
+        }
+
+        // Remove dupes
+        final Set<String> dedupPackages = new HashSet<>();
+        for (int i = mVisibleApps.size() - 1; i >= 0; i--) {
+            final SelectableAppInfo info = mVisibleApps.get(i);
+            if (DEBUG) Log.i(TAG, info.toString());
+            if (!TextUtils.isEmpty(info.packageName) && dedupPackages.contains(info.packageName)) {
+                mVisibleApps.remove(i);
+            } else {
+                dedupPackages.add(info.packageName);
+            }
+        }
+
+        // Sort the list of visible apps
+        mVisibleApps.sort(new AppLabelComparator());
+    }
+
+    /** Removes from {@link #mVisibleApps} all packages already installed on mUser. */
+    private void removeSecondUsersApp() {
+        // Get the set of apps already installed for mUser
+        final Set<String> userPackages = new HashSet<>();
+        final List<ApplicationInfo> userAppInfos = mPackageManager.getInstalledApplicationsAsUser(
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES, mUser.getIdentifier());
+        for (int i = userAppInfos.size() - 1; i >= 0; i--) {
+            final ApplicationInfo app = userAppInfos.get(i);
+            if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
+            userPackages.add(app.packageName);
+        }
+
+        for (int i = mVisibleApps.size() - 1; i >= 0; i--) {
+            final SelectableAppInfo info = mVisibleApps.get(i);
+            if (DEBUG) Log.i(TAG, info.toString());
+            if (!TextUtils.isEmpty(info.packageName) && userPackages.contains(info.packageName)) {
+                mVisibleApps.remove(i);
+            }
+        }
+    }
+
+    /**
+     * Add system apps that match an intent to the list.
+     * @param visibleApps list of apps to append the new list to
+     * @param intent the intent to match
+     */
+    private void addSystemApps(List<SelectableAppInfo> visibleApps, Intent intent) {
+        final List<ResolveInfo> intentApps = mPackageManager.queryIntentActivities(intent, 0);
+        for (ResolveInfo app : intentApps) {
+            if (app.activityInfo != null && app.activityInfo.applicationInfo != null) {
+                final int flags = app.activityInfo.applicationInfo.flags;
+                if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                        || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+
+                    final SelectableAppInfo info = new SelectableAppInfo();
+                    info.packageName = app.activityInfo.packageName;
+                    info.appName = app.activityInfo.applicationInfo.loadLabel(mPackageManager);
+                    info.icon = app.activityInfo.loadIcon(mPackageManager);
+
+                    visibleApps.add(info);
+                }
+            }
+        }
+    }
+
+    /** Container for a package, its name, and icon. */
+    public static class SelectableAppInfo {
+        public String packageName;
+        public CharSequence appName;
+        public Drawable icon;
+
+        @Override
+        public String toString() {
+            return packageName + ": appName=" + appName + "; icon=" + icon;
+        }
+    }
+
+    private static class AppLabelComparator implements Comparator<SelectableAppInfo> {
+        @Override
+        public int compare(SelectableAppInfo lhs, SelectableAppInfo rhs) {
+            String lhsLabel = lhs.appName.toString();
+            String rhsLabel = rhs.appName.toString();
+            return lhsLabel.toLowerCase().compareTo(rhsLabel.toLowerCase());
+        }
+    }
+
+    /**
+     * Unit test will subclass it to inject mocks.
+     */
+    @VisibleForTesting
+    static class Injector {
+        private final Context mContext;
+        private final UserHandle mUser;
+
+        Injector(Context context, UserHandle user) {
+            mContext = context;
+            mUser = user;
+        }
+
+        UserHandle getUser() {
+            return mUser;
+        }
+
+        PackageManager getPackageManager() {
+            return mContext.getPackageManager();
+        }
+
+        IPackageManager getIPackageManager() {
+            return AppGlobals.getPackageManager();
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 72fa25f..bf0dc7b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -157,7 +157,6 @@
     private Network mDefaultNetwork = null;
     private NetworkCapabilities mDefaultNetworkCapabilities = null;
     private final Runnable mCallback;
-    private final boolean mSupportMergedUi;
 
     private WifiInfo mWifiInfo;
     public boolean enabled;
@@ -181,7 +180,6 @@
         mNetworkScoreManager = networkScoreManager;
         mConnectivityManager = connectivityManager;
         mCallback = callback;
-        mSupportMergedUi = false;
     }
 
     public void setListening(boolean listening) {
@@ -223,10 +221,8 @@
                 } else {
                     ssid = getValidSsid(mWifiInfo);
                 }
-                if (mSupportMergedUi) {
-                    isCarrierMerged = mWifiInfo.isCarrierMerged();
-                    subId = mWifiInfo.getSubscriptionId();
-                }
+                isCarrierMerged = mWifiInfo.isCarrierMerged();
+                subId = mWifiInfo.getSubscriptionId();
                 updateRssi(mWifiInfo.getRssi());
                 maybeRequestNetworkScore();
             }
@@ -255,10 +251,8 @@
             } else {
                 ssid = getValidSsid(mWifiInfo);
             }
-            if (mSupportMergedUi) {
-                isCarrierMerged = mWifiInfo.isCarrierMerged();
-                subId = mWifiInfo.getSubscriptionId();
-            }
+            isCarrierMerged = mWifiInfo.isCarrierMerged();
+            subId = mWifiInfo.getSubscriptionId();
             updateRssi(mWifiInfo.getRssi());
             maybeRequestNetworkScore();
         }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java
new file mode 100644
index 0000000..111bcc4
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
+
+import com.android.settingslib.BaseTest;
+
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests for AppCopyHelper.
+ */
+@SmallTest
+public class AppCopyingHelperTest extends BaseTest {
+    private @Mock Context mContext;
+    private @Mock PackageManager mPm;
+    private @Mock IPackageManager mIpm;
+
+    private final UserHandle mTestUser = UserHandle.of(1111);
+    private AppCopyHelper mHelper;
+
+    private final ArrayList<ApplicationInfo> mCurrUserInstalledAppInfos = new ArrayList<>();
+    private final ArrayList<ApplicationInfo> mTestUserInstalledAppInfos = new ArrayList<>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        mHelper = new AppCopyHelper(new TestInjector());
+    }
+
+    public void testFetchAndMergeApps() throws Exception {
+        // Apps on the current user.
+        final String[] sysInapplicables = new String[] {"sys.no0, sys.no1"};
+        final String[] sysLaunchables = new String[] {"sys1", "sys2", "sys3"};
+        final String[] sysWidgets = new String[] {"sys1", "sys4"};
+        final String[] downloadeds = new String[] {"app1", "app2"};
+
+        addInapplicableSystemApps(sysInapplicables);
+        addSystemAppsForIntent(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER),
+                sysLaunchables);
+        addSystemAppsForIntent(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
+                sysWidgets);
+        addDownloadedApps(downloadeds);
+        when(mPm.getInstalledApplications(anyInt())).thenReturn(mCurrUserInstalledAppInfos);
+
+        // Apps on the test user.
+        final String[] testUserApps =
+                new String[]{"sys.no0", "sys2", "sys4", "app2", "sys999", "app999"};
+        addAppsToTestUser(testUserApps);
+        when(mPm.getInstalledApplicationsAsUser(anyInt(), eq(mTestUser.getIdentifier())))
+                .thenReturn(mTestUserInstalledAppInfos);
+
+        mHelper.fetchAndMergeApps();
+
+        final ArraySet<String> notExpectedInVisibleApps = new ArraySet<>();
+        Collections.addAll(notExpectedInVisibleApps, sysInapplicables);
+        Collections.addAll(notExpectedInVisibleApps, testUserApps);
+
+        final ArraySet<String> expectedInVisibleApps = new ArraySet<>();
+        Collections.addAll(expectedInVisibleApps, sysLaunchables);
+        Collections.addAll(expectedInVisibleApps, sysWidgets);
+        Collections.addAll(expectedInVisibleApps, downloadeds);
+        expectedInVisibleApps.removeAll(notExpectedInVisibleApps);
+
+        for (AppCopyHelper.SelectableAppInfo info : mHelper.getVisibleApps()) {
+            if (expectedInVisibleApps.contains(info.packageName)) {
+                expectedInVisibleApps.remove(info.packageName);
+            } else if (notExpectedInVisibleApps.contains(info.packageName)) {
+                fail("Package: " + info.packageName + " should not be included in visibleApps");
+            } else {
+                fail("Unknown package: " + info.packageName);
+            }
+        }
+        assertEquals("Some expected apps are not included in visibleApps: " + expectedInVisibleApps,
+                0, expectedInVisibleApps.size());
+    }
+
+    public void testInstallSelectedApps() throws Exception {
+        final int testUserId = mTestUser.getIdentifier();
+
+        mHelper.setPackageSelected("app1", true); // Ultimately true
+        mHelper.setPackageSelected("app2", true); // Ultimately false
+        mHelper.setPackageSelected("app3", true); // Ultimately true
+        mHelper.setPackageSelected("app4", true); // Ultimately true
+
+        mHelper.setPackageSelected("app2", false);
+        mHelper.setPackageSelected("app1", false);
+        mHelper.setPackageSelected("app1", true);
+
+
+        // app3 is installed but hidden
+        ApplicationInfo info = new ApplicationInfo();
+        info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+        info.flags |= ApplicationInfo.FLAG_INSTALLED;
+        when(mIpm.getApplicationInfo(eq("app3"), anyInt(), eq(testUserId)))
+                .thenReturn(info);
+
+        info = new ApplicationInfo();
+        when(mIpm.getApplicationInfo(eq("app4"), anyInt(), eq(testUserId)))
+                .thenReturn(info);
+
+        mHelper.installSelectedApps();
+
+        verify(mIpm, times(1)).installExistingPackageAsUser(
+                "app1", testUserId,
+                PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+                PackageManager.INSTALL_REASON_UNKNOWN, null);
+        verify(mIpm, times(0)).installExistingPackageAsUser(eq(
+                "app2"), eq(testUserId),
+                anyInt(), anyInt(), any());
+        verify(mIpm, times(0)).installExistingPackageAsUser(eq(
+                "app3"), eq(testUserId),
+                anyInt(), anyInt(), any());
+        verify(mIpm, times(1)).installExistingPackageAsUser(
+                "app4", testUserId,
+                PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+                PackageManager.INSTALL_REASON_UNKNOWN, null);
+
+        verify(mIpm, times(0)).setApplicationHiddenSettingAsUser(
+                eq("app1"), anyBoolean(), eq(testUserId));
+        verify(mIpm, times(0)).setApplicationHiddenSettingAsUser(
+                eq("app2"), anyBoolean(), eq(testUserId));
+        verify(mIpm, times(1)).setApplicationHiddenSettingAsUser(
+                eq("app3"), eq(false), eq(testUserId));
+        verify(mIpm, times(0)).setApplicationHiddenSettingAsUser(
+                eq("app4"), anyBoolean(), eq(testUserId));
+    }
+
+    private void addSystemAppsForIntent(Intent intent, String... packages) throws Exception {
+        final List<ResolveInfo> resolveInfos = new ArrayList<>();
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
+            resolveInfos.add(ri);
+            addInstalledApp(ri, false);
+        }
+        when(mPm.queryIntentActivities(argThat(new IntentMatcher(intent)), anyInt()))
+                .thenReturn(resolveInfos);
+    }
+
+    private void addInapplicableSystemApps(String... packages) throws Exception {
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
+            addInstalledApp(ri, false);
+        }
+    }
+
+    private void addDownloadedApps(String... packages) throws Exception {
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfo(pkg);
+            addInstalledApp(ri, false);
+        }
+    }
+
+    private void addAppsToTestUser(String... packages) throws Exception {
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfo(pkg);
+            addInstalledApp(ri, true);
+        }
+    }
+
+    private void addInstalledApp(ResolveInfo ri, boolean testUser)
+            throws PackageManager.NameNotFoundException {
+        final String pkgName = ri.activityInfo.packageName;
+        final PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = ri.activityInfo.applicationInfo;
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+        if (testUser) {
+            mTestUserInstalledAppInfos.add(packageInfo.applicationInfo);
+        } else {
+            mCurrUserInstalledAppInfos.add(packageInfo.applicationInfo);
+        }
+        when(mPm.getPackageInfo(eq(pkgName), anyInt())).thenReturn(packageInfo);
+    }
+
+    private ResolveInfo createResolveInfoForSystemApp(String packageName) {
+        final ResolveInfo ri = createResolveInfo(packageName);
+        ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        ri.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        return ri;
+    }
+
+    private ResolveInfo createResolveInfo(String packageName) {
+        final ResolveInfo ri = new ResolveInfo();
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = packageName;
+        final ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.applicationInfo = applicationInfo;
+        activityInfo.packageName = packageName;
+        activityInfo.name = "";
+        ri.activityInfo = activityInfo;
+        final ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.applicationInfo = applicationInfo;
+        serviceInfo.packageName = packageName;
+        serviceInfo.name = "";
+        ri.serviceInfo = serviceInfo;
+        return ri;
+    }
+
+    private static class IntentMatcher implements ArgumentMatcher<Intent> {
+        private final Intent mIntent;
+
+        IntentMatcher(Intent intent) {
+            mIntent = intent;
+        }
+
+        @Override
+        public boolean matches(Intent argument) {
+            return argument != null && argument.filterEquals(mIntent);
+        }
+
+        @Override
+        public String toString() {
+            return "Expected: " + mIntent;
+        }
+    }
+
+    private class TestInjector extends AppCopyHelper.Injector {
+        TestInjector() {
+            super(mContext, mTestUser);
+        }
+
+        @Override
+        UserHandle getUser() {
+            return mTestUser;
+        }
+
+        @Override
+        PackageManager getPackageManager() {
+            return mPm;
+        }
+
+        @Override
+        IPackageManager getIPackageManager() {
+            return mIpm;
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
new file mode 100644
index 0000000..4e2b63b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.settingslib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class PrimarySwitchPreferenceTest {
+
+    private Context mContext;
+    private PrimarySwitchPreference mPreference;
+    private PreferenceViewHolder mHolder;
+    private LinearLayout mWidgetView;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mPreference = new PrimarySwitchPreference(mContext);
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
+                com.android.settingslib.R.layout.preference_two_target, null));
+        mWidgetView = mHolder.itemView.findViewById(android.R.id.widget_frame);
+        inflater.inflate(R.layout.restricted_preference_widget_primary_switch, mWidgetView, true);
+    }
+
+    @Test
+    public void createNewPreference_shouldSetLayout() {
+        assertThat(mPreference.getWidgetLayoutResource())
+                .isEqualTo(R.layout.restricted_preference_widget_primary_switch);
+    }
+
+    @Test
+    public void setChecked_shouldUpdateButtonCheckedState() {
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        mPreference.onBindViewHolder(mHolder);
+
+        mPreference.setChecked(true);
+        assertThat(toggle.isChecked()).isTrue();
+
+        mPreference.setChecked(false);
+        assertThat(toggle.isChecked()).isFalse();
+    }
+
+    @Test
+    public void setSwitchEnabled_shouldUpdateButtonEnabledState() {
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        mPreference.onBindViewHolder(mHolder);
+
+        mPreference.setSwitchEnabled(true);
+        assertThat(toggle.isEnabled()).isTrue();
+
+        mPreference.setSwitchEnabled(false);
+        assertThat(toggle.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void setSwitchEnabled_shouldUpdateButtonEnabledState_beforeViewBound() {
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+
+        mPreference.setSwitchEnabled(false);
+        mPreference.onBindViewHolder(mHolder);
+        assertThat(toggle.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void clickWidgetView_shouldToggleButton() {
+        assertThat(mWidgetView).isNotNull();
+
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        mPreference.onBindViewHolder(mHolder);
+
+        toggle.performClick();
+        assertThat(toggle.isChecked()).isTrue();
+
+        toggle.performClick();
+        assertThat(toggle.isChecked()).isFalse();
+    }
+
+    @Test
+    public void clickWidgetView_shouldNotToggleButtonIfDisabled() {
+        assertThat(mWidgetView).isNotNull();
+
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        mPreference.onBindViewHolder(mHolder);
+        toggle.setEnabled(false);
+
+        mWidgetView.performClick();
+        assertThat(toggle.isChecked()).isFalse();
+    }
+
+    @Test
+    public void clickWidgetView_shouldNotifyPreferenceChanged() {
+
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+
+        final OnPreferenceChangeListener listener = mock(OnPreferenceChangeListener.class);
+        mPreference.setOnPreferenceChangeListener(listener);
+        mPreference.onBindViewHolder(mHolder);
+
+        mPreference.setChecked(false);
+        toggle.performClick();
+        verify(listener).onPreferenceChange(mPreference, true);
+
+        mPreference.setChecked(true);
+        toggle.performClick();
+        verify(listener).onPreferenceChange(mPreference, false);
+    }
+
+    @Test
+    public void setDisabledByAdmin_hasEnforcedAdmin_shouldDisableButton() {
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        toggle.setEnabled(true);
+        mPreference.onBindViewHolder(mHolder);
+
+        mPreference.setDisabledByAdmin(mock(EnforcedAdmin.class));
+        assertThat(toggle.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void setDisabledByAdmin_noEnforcedAdmin_shouldEnableButton() {
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        toggle.setEnabled(false);
+        mPreference.onBindViewHolder(mHolder);
+
+        mPreference.setDisabledByAdmin(null);
+        assertThat(toggle.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onBindViewHolder_toggleButtonShouldHaveContentDescription() {
+        final Switch toggle = (Switch) mHolder.findViewById(R.id.switchWidget);
+        final String label = "TestButton";
+        mPreference.setTitle(label);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(toggle.getContentDescription()).isEqualTo(label);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
similarity index 72%
rename from packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
rename to packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
index 16d73a3..cb62a73 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
@@ -1,15 +1,34 @@
-package com.android.settingslib.location;
+/*
+ * 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.settingslib.applications;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
 import android.content.Context;
+import android.content.PermissionChecker;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -19,13 +38,14 @@
 import android.util.LongSparseArray;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowPermissionChecker;
 
 import java.time.Clock;
 import java.util.ArrayList;
@@ -34,7 +54,8 @@
 import java.util.concurrent.TimeUnit;
 
 @RunWith(RobolectricTestRunner.class)
-public class RecentLocationAccessesTest {
+@Config(shadows = {ShadowPermissionChecker.class})
+public class RecentAppOpsAccessesTest {
 
     private static final int TEST_UID = 1234;
     private static final long NOW = 1_000_000_000;  // Approximately 9/8/2001
@@ -54,7 +75,7 @@
     private Clock mClock;
     private Context mContext;
     private int mTestUserId;
-    private RecentLocationAccesses mRecentLocationAccesses;
+    private RecentAppOpsAccess mRecentAppOpsAccess;
 
     @Before
     public void setUp() throws NameNotFoundException {
@@ -69,24 +90,37 @@
                 .thenReturn("testApplicationLabel");
         when(mPackageManager.getUserBadgedLabel(isA(CharSequence.class), isA(UserHandle.class)))
                 .thenReturn("testUserBadgedLabel");
+        when(mPackageManager.getPermissionFlags(any(), any(), any()))
+                .thenReturn(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+                        | PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED);
+        for (String testPackageName : TEST_PACKAGE_NAMES) {
+            ShadowPermissionChecker.setResult(
+                    testPackageName,
+                    Manifest.permission.ACCESS_COARSE_LOCATION,
+                    PermissionChecker.PERMISSION_GRANTED);
+            ShadowPermissionChecker.setResult(
+                    testPackageName,
+                    Manifest.permission.ACCESS_FINE_LOCATION,
+                    PermissionChecker.PERMISSION_GRANTED);
+        }
         mTestUserId = UserHandle.getUserId(TEST_UID);
         when(mUserManager.getUserProfiles())
                 .thenReturn(Collections.singletonList(new UserHandle(mTestUserId)));
 
         long[] testRequestTime = {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO};
         List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
-        when(mAppOpsManager.getPackagesForOps(RecentLocationAccesses.LOCATION_OPS)).thenReturn(
+        when(mAppOpsManager.getPackagesForOps(RecentAppOpsAccess.LOCATION_OPS)).thenReturn(
                 appOps);
         mockTestApplicationInfos(mTestUserId, TEST_PACKAGE_NAMES);
 
         when(mClock.millis()).thenReturn(NOW);
-        mRecentLocationAccesses = new RecentLocationAccesses(mContext, mClock);
+        mRecentAppOpsAccess = new RecentAppOpsAccess(mContext, mClock,
+                RecentAppOpsAccess.LOCATION_OPS);
     }
 
     @Test
-    @Ignore
     public void testGetAppList_shouldFilterRecentAccesses() {
-        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList(false);
+        List<RecentAppOpsAccess.Access> requests = mRecentAppOpsAccess.getAppList(false);
         // Only two of the apps have requested location within 15 min.
         assertThat(requests).hasSize(2);
         // Make sure apps are ordered by recency
@@ -97,12 +131,11 @@
     }
 
     @Test
-    @Ignore
     public void testGetAppList_shouldNotShowAndroidOS() throws NameNotFoundException {
         // Add android OS to the list of apps.
         PackageOps androidSystemPackageOps =
                 createPackageOps(
-                        RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME,
+                        RecentAppOpsAccess.ANDROID_SYSTEM_PACKAGE_NAME,
                         Process.SYSTEM_UID,
                         AppOpsManager.OP_FINE_LOCATION,
                         ONE_MIN_AGO);
@@ -110,12 +143,12 @@
                 {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO, ONE_MIN_AGO};
         List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
         appOps.add(androidSystemPackageOps);
-        when(mAppOpsManager.getPackagesForOps(RecentLocationAccesses.LOCATION_OPS)).thenReturn(
+        when(mAppOpsManager.getPackagesForOps(RecentAppOpsAccess.LOCATION_OPS)).thenReturn(
                 appOps);
         mockTestApplicationInfos(
-                Process.SYSTEM_UID, RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME);
+                Process.SYSTEM_UID, RecentAppOpsAccess.ANDROID_SYSTEM_PACKAGE_NAME);
 
-        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList(true);
+        List<RecentAppOpsAccess.Access> requests = mRecentAppOpsAccess.getAppList(true);
         // Android OS shouldn't show up in the list of apps.
         assertThat(requests).hasSize(2);
         // Make sure apps are ordered by recency
@@ -159,7 +192,7 @@
         // Slot for background access timestamp.
         final LongSparseArray<AppOpsManager.NoteOpEvent> accessEvents = new LongSparseArray<>();
         accessEvents.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_BACKGROUND,
-            AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, -1, null));
+                AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, -1, null));
 
         return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
                 new AppOpsManager.AttributedOpEntry(op, false, accessEvents, null)));
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/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 0ad8f39d..80b7e10 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -81,5 +81,6 @@
         Settings.Global.POWER_BUTTON_LONG_PRESS,
         Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
         Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
+        Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 6022608..96f127b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -101,6 +101,7 @@
         Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
         Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
         Settings.Secure.QS_TILES,
+        Settings.Secure.QS_AUTO_ADDED_TILES,
         Settings.Secure.CONTROLS_ENABLED,
         Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
         Settings.Secure.DOZE_ENABLED,
@@ -118,7 +119,6 @@
         Settings.Secure.VR_DISPLAY_MODE,
         Settings.Secure.NOTIFICATION_BADGING,
         Settings.Secure.NOTIFICATION_DISMISS_RTL,
-        Settings.Secure.QS_AUTO_ADDED_TILES,
         Settings.Secure.SCREENSAVER_ENABLED,
         Settings.Secure.SCREENSAVER_COMPONENTS,
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 9bc8e65..0a75eb8 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.NONE_NEGATIVE_LONG_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;
@@ -118,6 +119,10 @@
         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);
@@ -147,6 +152,7 @@
         VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.AUTOMATIC_POWER_SAVE_MODE, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.ADVANCED_BATTERY_USAGE_AMOUNT, PERCENTAGE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, NONE_NEGATIVE_LONG_VALIDATOR);
 
         VALIDATORS.put(Global.Wearable.HAS_PAY_TOKENS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, ANY_INTEGER_VALIDATOR);
@@ -313,6 +319,8 @@
                 NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.WRIST_ORIENTATION_MODE,
+                       new DiscreteValueValidator(new String[] {"0", "1", "2", "3"}));
     }
 }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index c577868..6cfcb51 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -72,8 +72,9 @@
      * {@hide}
      */
     private static final ArraySet<String> sBroadcastOnRestore;
+    private static final ArraySet<String> sBroadcastOnRestoreSystemUI;
     static {
-        sBroadcastOnRestore = new ArraySet<String>(4);
+        sBroadcastOnRestore = new ArraySet<String>(9);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -83,6 +84,9 @@
         sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
         sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
         sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
+        sBroadcastOnRestoreSystemUI = new ArraySet<String>(2);
+        sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES);
+        sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_AUTO_ADDED_TILES);
     }
 
     private interface SettingsLookup {
@@ -133,6 +137,7 @@
         // Will we need a post-restore broadcast for this element?
         String oldValue = null;
         boolean sendBroadcast = false;
+        boolean sendBroadcastSystemUI = false;
         final SettingsLookup table;
 
         if (destination.equals(Settings.Secure.CONTENT_URI)) {
@@ -143,10 +148,12 @@
             table = sGlobalLookup;
         }
 
-        if (sBroadcastOnRestore.contains(name)) {
+        sendBroadcast = sBroadcastOnRestore.contains(name);
+        sendBroadcastSystemUI = sBroadcastOnRestoreSystemUI.contains(name);
+
+        if (sendBroadcast || sendBroadcastSystemUI) {
             // TODO: http://b/22388012
             oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM);
-            sendBroadcast = true;
         }
 
         try {
@@ -193,18 +200,28 @@
         } catch (Exception e) {
             // If we fail to apply the setting, by definition nothing happened
             sendBroadcast = false;
+            sendBroadcastSystemUI = false;
         } finally {
             // If this was an element of interest, send the "we just restored it"
             // broadcast with the historical value now that the new value has
             // been committed and observers kicked off.
-            if (sendBroadcast) {
+            if (sendBroadcast || sendBroadcastSystemUI) {
                 Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
-                        .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+                        .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                         .putExtra(Intent.EXTRA_SETTING_NAME, name)
                         .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value)
                         .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue)
                         .putExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, restoredFromSdkInt);
-                context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
+
+                if (sendBroadcast) {
+                    intent.setPackage("android");
+                    context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
+                }
+                if (sendBroadcastSystemUI) {
+                    intent.setPackage(
+                            context.getString(com.android.internal.R.string.config_systemUi));
+                    context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
+                }
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 579c3a5..4ac1938 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1192,6 +1192,9 @@
         dumpSetting(s, p,
                 Settings.Global.POWER_MANAGER_CONSTANTS,
                 GlobalSettingsProto.POWER_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS,
+                GlobalSettingsProto.POWER_BUTTON_LONG_PRESS_DURATION_MS);
 
         final long prepaidSetupToken = p.start(GlobalSettingsProto.PREPAID_SETUP);
         dumpSetting(s, p,
@@ -1473,6 +1476,9 @@
                 Settings.Global.USE_OPEN_WIFI_PACKAGE,
                 GlobalSettingsProto.USE_OPEN_WIFI_PACKAGE);
         dumpSetting(s, p,
+                Settings.Global.UWB_ENABLED,
+                GlobalSettingsProto.UWB_ENABLED);
+        dumpSetting(s, p,
                 Settings.Global.VT_IMS_ENABLED,
                 GlobalSettingsProto.VT_IMS_ENABLED);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 294399e..25211b4 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;
 
@@ -5193,210 +5193,254 @@
                 }
 
                 if (currentVersion == 203) {
-                        // Version 203: initialize entries migrated from wear settings provide.
-                        initGlobalSettingsDefaultValForWearLocked(Global.Wearable.HAS_PAY_TOKENS,
-                                false);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, 6);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.HOTWORD_DETECTION_ENABLED,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_hotwordDetectionEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.SMART_REPLIES_ENABLED, false);
-                        Setting locationMode = getSecureSettingsLocked(userId)
-                                                        .getSettingLocked(Secure.LOCATION_MODE);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
-                                !locationMode.isNull()
-                                        && !Integer.toString(Secure.LOCATION_MODE_OFF)
-                                                .equals(locationMode.getValue()));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.RETAIL_MODE, Global.Wearable.RETAIL_MODE_CONSUMER);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                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?
-                                        ? Global.Wearable.BUG_REPORT_DISABLED
-                                        : Global.Wearable.BUG_REPORT_ENABLED);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.SMART_ILLUMINATE_ENABLED,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_smartIlluminateEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.CLOCKWORK_AUTO_TIME,
-                                Global.Wearable.SYNC_TIME_FROM_PHONE);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
-                                Global.Wearable.SYNC_TIME_ZONE_FROM_PHONE);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.CLOCKWORK_24HR_TIME, false);
-                        initGlobalSettingsDefaultValForWearLocked(Global.Wearable.AUTO_WIFI, true);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.WIFI_POWER_SAVE,
-                                getContext()
-                                        .getResources()
-                                        .getInteger(
-                                                R.integer
+                    // Version 203: initialize entries migrated from wear settings provide.
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.HAS_PAY_TOKENS, false);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, 6);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.HOTWORD_DETECTION_ENABLED,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_hotwordDetectionEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.SMART_REPLIES_ENABLED, false);
+                    Setting locationMode =
+                            getSecureSettingsLocked(userId).getSettingLocked(Secure.LOCATION_MODE);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
+                            !locationMode.isNull()
+                                    && !Integer.toString(Secure.LOCATION_MODE_OFF)
+                                            .equals(locationMode.getValue()));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.RETAIL_MODE, Global.Wearable.RETAIL_MODE_CONSUMER);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            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?
+                                    ? Global.Wearable.BUG_REPORT_DISABLED
+                                    : Global.Wearable.BUG_REPORT_ENABLED);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.SMART_ILLUMINATE_ENABLED,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_smartIlluminateEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.CLOCKWORK_AUTO_TIME,
+                            Global.Wearable.SYNC_TIME_FROM_PHONE);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
+                            Global.Wearable.SYNC_TIME_ZONE_FROM_PHONE);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.CLOCKWORK_24HR_TIME, false);
+                    initGlobalSettingsDefaultValForWearLocked(Global.Wearable.AUTO_WIFI, true);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.WIFI_POWER_SAVE,
+                            getContext()
+                                    .getResources()
+                                    .getInteger(
+                                            R.integer
                                                     .def_wearable_offChargerWifiUsageLimitMinutes));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS, 0L);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.UPDOWN_GESTURES_ENABLED,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_upDownGesturesEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.SETUP_SKIPPED,
-                                Global.Wearable.SETUP_SKIPPED_UNKNOWN);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.LAST_CALL_FORWARD_ACTION,
-                                Global.Wearable.CALL_FORWARD_NO_LAST_ACTION);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_muteWhenOffBodyEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.WEAR_OS_VERSION_STRING, "");
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.ALTERNATE_LAUNCHER_ENABLED,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_alternateLauncherEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.CORNER_ROUNDNESS,
-                                getContext()
-                                        .getResources()
-                                        .getInteger(
-                                                R.integer
-                                                        .def_wearable_squareScreenCornerRoundness));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.BUTTON_SET, false);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.SIDE_BUTTON,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_sideButtonPresent));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.ANDROID_WEAR_VERSION,
-                                Long.parseLong(
-                                        getContext()
-                                                .getResources()
-                                                .getString(
-                                                        R.string.def_wearable_androidWearVersion)));
-                        final int editionGlobal = 1;
-                        final int editionLocal = 2;
-                        boolean isLe =
-                                getContext().getPackageManager().hasSystemFeature("cn.google");
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.SYSTEM_EDITION,
-                                isLe ? editionLocal : editionGlobal);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.SYSTEM_CAPABILITIES,
-                                getWearSystemCapabilities(isLe));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.WEAR_PLATFORM_MR_NUMBER,
-                                SystemProperties.getInt("ro.cw_build.platform_mr", 0));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.BOTTOM_OFFSET, 0);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.DISPLAY_SHAPE,
-                                Settings.Global.Wearable.DISPLAY_SHAPE_SQUARE);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.SCREEN_BRIGHTNESS_LEVEL,
-                                getContext()
-                                        .getResources()
-                                        .getString(R.string.def_wearable_brightnessLevels));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(
-                                                R.bool.def_wearable_mobileSignalDetectorAllowed));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.AMBIENT_ENABLED,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_ambientEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.AMBIENT_TILT_TO_WAKE,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_tiltToWakeEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.AMBIENT_LOW_BIT_ENABLED_DEV, false);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.AMBIENT_TOUCH_TO_WAKE,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_touchToWakeEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.AMBIENT_TILT_TO_BRIGHT,
-                                getContext()
-                                        .getResources()
-                                        .getBoolean(R.bool.def_wearable_tiltToBrightEnabled));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.DECOMPOSABLE_WATCHFACE, false);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED,
-                                SystemProperties.getBoolean("ro.ambient.force_when_docked", false));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.AMBIENT_GESTURE_SENSOR_ID,
-                                SystemProperties.getInt("ro.ambient.gesture_sensor_id", 0));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED,
-                                SystemProperties.getBoolean("ro.ambient.low_bit_enabled", false));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.AMBIENT_PLUGGED_TIMEOUT_MIN,
-                                SystemProperties.getInt("ro.ambient.plugged_timeout_min", -1));
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.COMPANION_ADDRESS, "");
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE,
-                                Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE_UNKNOWN);
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.USER_HFP_CLIENT_SETTING,
-                                Settings.Global.Wearable.HFP_CLIENT_UNSET);
-                        Setting disabledProfileSetting =
-                                getGlobalSettingsLocked()
-                                        .getSettingLocked(
-                                                Settings.Global.BLUETOOTH_DISABLED_PROFILES);
-                        final long disabledProfileSettingValue =
-                                disabledProfileSetting.isNull()
-                                        ? 0
-                                        : Long.parseLong(disabledProfileSetting.getValue());
-                        final boolean isHfpClientProfileEnabled =
-                                (disabledProfileSettingValue
-                                                & (1 << BluetoothProfile.HEADSET_CLIENT))
-                                        == 0;
-                        initGlobalSettingsDefaultValForWearLocked(
-                                Settings.Global.Wearable.HFP_CLIENT_PROFILE_ENABLED,
-                                isHfpClientProfileEnabled);
-                        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);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS, 0L);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.UPDOWN_GESTURES_ENABLED,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_upDownGesturesEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.SETUP_SKIPPED, Global.Wearable.SETUP_SKIPPED_UNKNOWN);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.LAST_CALL_FORWARD_ACTION,
+                            Global.Wearable.CALL_FORWARD_NO_LAST_ACTION);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_muteWhenOffBodyEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.WEAR_OS_VERSION_STRING, "");
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.ALTERNATE_LAUNCHER_ENABLED,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_alternateLauncherEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.CORNER_ROUNDNESS,
+                            getContext()
+                                    .getResources()
+                                    .getInteger(
+                                            R.integer.def_wearable_squareScreenCornerRoundness));
+                    initGlobalSettingsDefaultValForWearLocked(Global.Wearable.BUTTON_SET, false);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.SIDE_BUTTON,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_sideButtonPresent));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.ANDROID_WEAR_VERSION,
+                            Long.parseLong(
+                                    getContext()
+                                            .getResources()
+                                            .getString(R.string.def_wearable_androidWearVersion)));
+                    final int editionGlobal = 1;
+                    final int editionLocal = 2;
+                    boolean isLe = getContext().getPackageManager().hasSystemFeature("cn.google");
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.SYSTEM_EDITION, isLe ? editionLocal : editionGlobal);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.SYSTEM_CAPABILITIES, getWearSystemCapabilities(isLe));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.WEAR_PLATFORM_MR_NUMBER,
+                            SystemProperties.getInt("ro.cw_build.platform_mr", 0));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.BOTTOM_OFFSET, 0);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.DISPLAY_SHAPE,
+                            Settings.Global.Wearable.DISPLAY_SHAPE_SQUARE);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.SCREEN_BRIGHTNESS_LEVEL,
+                            getContext()
+                                    .getResources()
+                                    .getString(R.string.def_wearable_brightnessLevels));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_mobileSignalDetectorAllowed));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.AMBIENT_ENABLED,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_ambientEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.AMBIENT_TILT_TO_WAKE,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_tiltToWakeEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.AMBIENT_LOW_BIT_ENABLED_DEV, false);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.AMBIENT_TOUCH_TO_WAKE,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_touchToWakeEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.AMBIENT_TILT_TO_BRIGHT,
+                            getContext()
+                                    .getResources()
+                                    .getBoolean(R.bool.def_wearable_tiltToBrightEnabled));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Global.Wearable.DECOMPOSABLE_WATCHFACE, false);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED,
+                            SystemProperties.getBoolean("ro.ambient.force_when_docked", false));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.AMBIENT_GESTURE_SENSOR_ID,
+                            SystemProperties.getInt("ro.ambient.gesture_sensor_id", 0));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED,
+                            SystemProperties.getBoolean("ro.ambient.low_bit_enabled", false));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.AMBIENT_PLUGGED_TIMEOUT_MIN,
+                            SystemProperties.getInt("ro.ambient.plugged_timeout_min", -1));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.COMPANION_ADDRESS, "");
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE,
+                            Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE_UNKNOWN);
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.USER_HFP_CLIENT_SETTING,
+                            Settings.Global.Wearable.HFP_CLIENT_UNSET);
+                    Setting disabledProfileSetting =
+                            getGlobalSettingsLocked()
+                                    .getSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES);
+                    final long disabledProfileSettingValue =
+                            disabledProfileSetting.isNull()
+                                    ? 0
+                                    : Long.parseLong(disabledProfileSetting.getValue());
+                    final boolean isHfpClientProfileEnabled =
+                            (disabledProfileSettingValue & (1 << BluetoothProfile.HEADSET_CLIENT))
+                                    == 0;
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.HFP_CLIENT_PROFILE_ENABLED,
+                            isHfpClientProfileEnabled);
+                    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;
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE,
+                            getContext()
+                                    .getResources()
+                                    .getString(
+                                            com.android.internal.R.string.config_wearSysUiPackage));
+                    initGlobalSettingsDefaultValForWearLocked(
+                            Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY,
+                            getContext()
+                                    .getResources()
+                                    .getString(
+                                            com.android
+                                                    .internal
+                                                    .R
+                                                    .string
+                                                    .config_wearSysUiMainActivity));
+
+                    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.
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index ec2ec66..df7bf20 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -266,10 +266,13 @@
                     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,
                     Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+                    Settings.Global.ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
                     Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT,
                     Settings.Global.ENABLE_MULTI_SLOT_TIMEOUT_MILLIS,
                     Settings.Global.ENHANCED_4G_MODE_ENABLED,
@@ -474,6 +477,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,
@@ -519,6 +524,7 @@
                     Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST,
                     Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST,
                     Settings.Global.UPDATABLE_DRIVER_SPHAL_LIBRARIES,
+                    Settings.Global.UWB_ENABLED,
                     Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX,
                     Settings.Global.GPU_DEBUG_LAYER_APP,
                     Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
@@ -661,7 +667,10 @@
                     Settings.Global.Wearable.MASTER_GESTURES_ENABLED,
                     Settings.Global.Wearable.UNGAZE_ENABLED,
                     Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
-                    Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED);
+                    Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED,
+                    Settings.Global.Wearable.WRIST_ORIENTATION_MODE,
+                    Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE,
+                    Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY);
 
     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..2f86232 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -18,30 +18,30 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"షెల్"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"బగ్ రిపోర్ట్స్"</string>
-    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
-    <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
-    <string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ నివేదికకు వివరాలను జోడిస్తోంది"</string>
+    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ రిపోర్ట్‌ <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
+    <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ రిపోర్ట్‌ <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
+    <string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ రిపోర్ట్‌‌కు వివరాలను జోడిస్తోంది"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"దయచేసి వేచి ఉండండి..."</string>
-    <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"బగ్ నివేదిక త్వరలో ఫోన్‌లో కనిపిస్తుంది"</string>
-    <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి"</string>
-    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ నివేదికను షేర్ చేయడానికి నొక్కండి"</string>
-    <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
+    <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"బగ్ రిపోర్ట్‌ త్వరలో ఫోన్‌లో కనిపిస్తుంది"</string>
+    <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"మీ బగ్ రిపోర్ట్‌ను షేర్ చేయడానికి ఎంచుకోండి"</string>
+    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ రిపోర్ట్‌ను షేర్ చేయడానికి నొక్కండి"</string>
+    <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>
-    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"బగ్ నివేదిక వివరాలను జిప్ ఫైల్‌కు జోడించడం సాధ్యపడలేదు"</string>
+    <string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ రిపోర్ట్‌ ఫైల్‌ను చదవడం సాధ్యపడలేదు"</string>
+    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"బగ్ రిపోర్ట్‌ వివరాలను జిప్ ఫైల్‌కు జోడించడం సాధ్యపడలేదు"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"పేరు లేనివి"</string>
     <string name="bugreport_info_action" msgid="2158204228510576227">"వివరాలు"</string>
     <string name="bugreport_screenshot_action" msgid="8677781721940614995">"స్క్రీన్‌షాట్"</string>
     <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"స్క్రీన్‌షాట్ విజయవంతంగా తీయబడింది."</string>
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
-    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
+    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ రిపోర్ట్‌ <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
     <string name="bugreport_info_title" msgid="2306030793918239804">"బగ్ శీర్షిక"</string>
     <string name="bugreport_info_description" msgid="5072835127481627722">"బగ్ సారాంశం"</string>
     <string name="save" msgid="4781509040564835759">"సేవ్ చేయి"</string>
-    <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"బగ్ నివేదిక షేర్ చేయండి"</string>
+    <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"బగ్ రిపోర్ట్‌ షేర్ చేయండి"</string>
 </resources>
diff --git a/packages/SoundPicker/res/values-te/strings.xml b/packages/SoundPicker/res/values-te/strings.xml
index 10b4e7c..8f5c34a 100644
--- a/packages/SoundPicker/res/values-te/strings.xml
+++ b/packages/SoundPicker/res/values-te/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="ringtone_default" msgid="798836092118824500">"డిఫాల్ట్ రింగ్‌టోన్"</string>
+    <string name="ringtone_default" msgid="798836092118824500">"ఆటోమేటిక్ రింగ్‌టోన్"</string>
     <string name="notification_sound_default" msgid="8133121186242636840">"నోటిఫికేషన్ ఆటోమేటిక్ సౌండ్"</string>
     <string name="alarm_sound_default" msgid="4787646764557462649">"అలారం ఆటోమేటిక్ సౌండ్"</string>
     <string name="add_ringtone_text" msgid="6642389991738337529">"రింగ్‌టోన్‌ను జోడించు"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index adf441b..eb0bb77 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -463,6 +463,7 @@
         <!-- started from SensoryPrivacyService -->
         <activity android:name=".sensorprivacy.television.TvUnblockSensorActivity"
                   android:exported="true"
+                  android:launchMode="singleTop"
                   android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
                   android:theme="@style/BottomSheet"
                   android:finishOnCloseSystemDialogs="true">
@@ -656,10 +657,6 @@
         </service>
 
         <service
-            android:name=".communal.service.CommunalService"
-            android:exported="@bool/config_communalServiceEnabled"/>
-
-        <service
             android:name=".keyguard.KeyguardService"
             android:exported="true" />
 
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 24bffa1..31cf530 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -26,6 +26,17 @@
       ]
     },
     {
+      "name": "SystemUIGoogleTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
       // Permission indicators
       "name": "CtsPermission4TestCases",
       "options": [
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index a50efd7..9c1e129 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -5,7 +5,6 @@
 import android.animation.ValueAnimator
 import android.app.ActivityManager
 import android.app.ActivityTaskManager
-import android.app.AppGlobals
 import android.app.PendingIntent
 import android.app.TaskInfo
 import android.content.Context
@@ -44,6 +43,7 @@
     context: Context
 ) {
     companion object {
+        private const val DEBUG = false
         const val ANIMATION_DURATION = 500L
         private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
         private const val ANIMATION_DURATION_FADE_IN_WINDOW = 183L
@@ -75,8 +75,6 @@
         }
     }
 
-    private val packageManager = AppGlobals.getPackageManager()
-
     /** The interpolator used for the width, height, Y position and corner radius. */
     private val animationInterpolator = AnimationUtils.loadInterpolator(context,
             R.interpolator.launch_animation_interpolator_y)
@@ -100,6 +98,10 @@
      * If possible, you should pass the [packageName] of the intent that will be started so that
      * trampoline activity launches will also be animated.
      *
+     * If the device is currently locked, the user will have to unlock it before the intent is
+     * started unless [showOverLockscreen] is true. In that case, the activity will be started
+     * directly over the lockscreen.
+     *
      * This method will throw any exception thrown by [intentStarter].
      */
     @JvmOverloads
@@ -107,21 +109,22 @@
         controller: Controller?,
         animate: Boolean = true,
         packageName: String? = null,
+        showOverLockscreen: Boolean = false,
         intentStarter: (RemoteAnimationAdapter?) -> Int
     ) {
         if (controller == null || !animate) {
-            Log.d(TAG, "Starting intent with no animation")
+            Log.i(TAG, "Starting intent with no animation")
             intentStarter(null)
             controller?.callOnIntentStartedOnMainThread(willAnimate = false)
             return
         }
 
-        Log.d(TAG, "Starting intent with a launch animation")
         val runner = Runner(controller)
-        val isOnKeyguard = callback.isOnKeyguard()
+        val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
 
-        // Pass the RemoteAnimationAdapter to the intent starter only if we are not on the keyguard.
-        val animationAdapter = if (!isOnKeyguard) {
+        // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the
+        // keyguard with the animation
+        val animationAdapter = if (!hideKeyguardWithAnimation) {
             RemoteAnimationAdapter(
                     runner,
                     ANIMATION_DURATION,
@@ -149,9 +152,11 @@
         val willAnimate =
                 launchResult == ActivityManager.START_TASK_TO_FRONT ||
                         launchResult == ActivityManager.START_SUCCESS ||
-                        (launchResult == ActivityManager.START_DELIVERED_TO_TOP && isOnKeyguard)
+                        (launchResult == ActivityManager.START_DELIVERED_TO_TOP &&
+                                hideKeyguardWithAnimation)
 
-        Log.d(TAG, "launchResult=$launchResult willAnimate=$willAnimate isOnKeyguard=$isOnKeyguard")
+        Log.i(TAG, "launchResult=$launchResult willAnimate=$willAnimate " +
+                "hideKeyguardWithAnimation=$hideKeyguardWithAnimation")
         controller.callOnIntentStartedOnMainThread(willAnimate)
 
         // If we expect an animation, post a timeout to cancel it in case the remote animation is
@@ -160,7 +165,7 @@
             runner.postTimeout()
 
             // Hide the keyguard using the launch animation instead of the default unlock animation.
-            if (isOnKeyguard) {
+            if (hideKeyguardWithAnimation) {
                 callback.hideKeyguardWithAnimation(runner)
             }
         }
@@ -424,13 +429,16 @@
             nonApps: Array<out RemoteAnimationTarget>?,
             iCallback: IRemoteAnimationFinishedCallback?
         ) {
-            Log.d(TAG, "Remote animation started")
+            if (DEBUG) {
+                Log.d(TAG, "Remote animation started")
+            }
+
             val window = apps?.firstOrNull {
                 it.mode == RemoteAnimationTarget.MODE_OPENING
             }
 
             if (window == null) {
-                Log.d(TAG, "Aborting the animation as no window is opening")
+                Log.i(TAG, "Aborting the animation as no window is opening")
                 removeTimeout()
                 iCallback?.invoke()
                 controller.onLaunchAnimationCancelled()
@@ -474,7 +482,7 @@
             val endRadius = if (isExpandingFullyAbove) {
                 // Most of the time, expanding fully above the root view means expanding in full
                 // screen.
-                ScreenDecorationsUtils.getWindowCornerRadius(context.resources)
+                ScreenDecorationsUtils.getWindowCornerRadius(context)
             } else {
                 // This usually means we are in split screen mode, so 2 out of 4 corners will have
                 // a radius of 0.
@@ -500,7 +508,10 @@
             val launchContainerOverlay = launchContainer.overlay
             animator.addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
-                    Log.d(TAG, "Animation started")
+                    if (DEBUG) {
+                        Log.d(TAG, "Animation started")
+                    }
+
                     callback.setBlursDisabledForAppLaunch(true)
                     controller.onLaunchAnimationStart(isExpandingFullyAbove)
 
@@ -511,7 +522,10 @@
                 }
 
                 override fun onAnimationEnd(animation: Animator?) {
-                    Log.d(TAG, "Animation ended")
+                    if (DEBUG) {
+                        Log.d(TAG, "Animation ended")
+                    }
+
                     callback.setBlursDisabledForAppLaunch(false)
                     iCallback?.invoke()
                     controller.onLaunchAnimationEnd(isExpandingFullyAbove)
@@ -686,7 +700,7 @@
                 return
             }
 
-            Log.d(TAG, "Remote animation timed out")
+            Log.i(TAG, "Remote animation timed out")
             timedOut = true
             controller.onLaunchAnimationCancelled()
         }
@@ -696,7 +710,7 @@
                 return
             }
 
-            Log.d(TAG, "Remote animation was cancelled")
+            Log.i(TAG, "Remote animation was cancelled")
             cancelled = true
             removeTimeout()
             context.mainExecutor.execute {
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/android/uwb/SessionHandle.aidl b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
similarity index 75%
copy from core/java/android/uwb/SessionHandle.aidl
copy to packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
index 58a7dbb..d5b9243 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
-package android.uwb;
+package com.android.systemui.flags;
 
-parcelable SessionHandle;
+/**
+ * List of {@link Flag} objects for use in SystemUI.
+ */
+public class Flags {
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 7c81325..6d088f0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -60,8 +60,16 @@
      */
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
     void startActivity(Intent intent, boolean dismissShade);
+
+    default void startActivity(Intent intent, boolean dismissShade,
+            @Nullable ActivityLaunchAnimator.Controller animationController) {
+        startActivity(intent, dismissShade, animationController,
+                false /* showOverLockscreenWhenLocked */);
+    }
+
     void startActivity(Intent intent, boolean dismissShade,
-            @Nullable ActivityLaunchAnimator.Controller animationController);
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            boolean showOverLockscreenWhenLocked);
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
     void startActivity(Intent intent, boolean dismissShade, Callback callback);
     void postStartActivityDismissingKeyguard(Intent intent, int delay);
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/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index 2213d1c..9a9683d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -60,6 +60,10 @@
 
     public abstract int getDetailY();
 
+    public View getLabel() {
+        return null;
+    }
+
     public View getLabelContainer() {
         return null;
     }
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions.xml b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
new file mode 100644
index 0000000..dfc3e63
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
@@ -0,0 +1,105 @@
+<?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.
+-->
+
+<!-- Action buttons for footer in QS/QQS, containing settings button, power off button etc -->
+<com.android.systemui.qs.FooterActionsView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    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.FooterActionsView>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 6016aaf..28c6166 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -68,16 +68,6 @@
             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_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 7c54b90..a946318 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -20,8 +20,8 @@
 <com.android.keyguard.KeyguardPINView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/keyguard_pin_view"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:id="@+id/keyguard_pin_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         androidprv:layout_maxWidth="@dimen/keyguard_security_width"
@@ -52,7 +52,7 @@
 
             androidprv:layout_constraintTop_toTopOf="parent"
             androidprv:layout_constraintBottom_toTopOf="@id/key1"
-            androidprv:layout_constraintVertical_bias="1.0">
+            androidprv:layout_constraintVertical_bias="0.0">
 
             <com.android.keyguard.PasswordTextView
                 android:id="@+id/pinEntry"
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 967d5cb..2908bae 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জ হচ্ছে"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • দ্রুত চার্জ হচ্ছে"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ধীরে চার্জ হচ্ছে"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জ সাময়িকভাবে বন্ধ করা আছে"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জ করা সাময়িকভাবে বন্ধ রাখা হয়েছে"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"আপনার চার্জার সংযুক্ত করুন।"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"আনলক করতে মেনুতে টিপুন।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটওয়ার্ক লক করা আছে"</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index ac5a58e..5be92983 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird geladen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird schnell geladen"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird langsam geladen"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Aufladen vorübergehend eingeschränkt"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laden vorübergehend eingeschränkt"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Ladegerät anschließen."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Zum Entsperren die Menütaste drücken."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 38a7139..f8c8cad 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"En recharge : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"En recharge rapide : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"En recharge lente : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • recharge temporairement limitée"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge temporairement limitée"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Branchez votre chargeur."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur la touche Menu pour déverrouiller l\'appareil."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index a41cce7..e87ee92 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ઝડપથી ચાર્જિંગ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ધીમેથી ચાર્જિંગ"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ હંગામીરૂપે પ્રતિબંધિત કરવામાં આવ્યું છે"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જ કરવાનું થોડા સમય માટે મર્યાદિત કરવામાં આવ્યું છે"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"તમારું ચાર્જર કનેક્ટ કરો."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 6237075..edf8ab2 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan cepat"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan lambat"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengisian daya dibatasi untuk sementara"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengisian daya dibatasi sementara"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Hubungkan pengisi daya."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Jaringan terkunci"</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 4e7ac49..bbc5aa0 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה מהירה"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה איטית"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • הטעינה מוגבלת זמנית"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • הטעינה מוגבלת באופן זמני"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"כדאי לחבר את המטען."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"יש ללחוץ על \'תפריט\' כדי לבטל את הנעילה."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"הרשת נעולה"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index a1d58b7..60b52ea 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 急速充電中"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 低速充電中"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電は一時的に制限されています"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電を一時的に制限しています"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"充電してください。"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"メニューからロックを解除できます。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ネットワークがロックされました"</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index a0ae88a..eca4957 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្ម"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្មយឺត"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • បានដាក់កម្រិត​ការសាកថ្ម​ជាបណ្ដោះអាសន្ន"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • បានដាក់កំហិតលើ​ការសាកថ្មជា​បណ្ដោះអាសន្ន"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"សូមសាក​ថ្ម​របស់​អ្នក។"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ចុចម៉ឺនុយ ​ដើម្បី​ដោះ​សោ។"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"បណ្ដាញ​ជាប់​សោ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 98b1af6..5cbe02e 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ವೇಗವಾಗಿ ಚಾರ್ಜ್‌ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜಿಂಗ್ ತಾತ್ಕಾಲಿಕವಾಗಿ ಸೀಮಿತವಾಗಿದೆ"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಸೀಮಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"ನಿಮ್ಮ ಚಾರ್ಜರ್ ಸಂಪರ್ಕಗೊಳಿಸಿ."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ನೆಟ್‌ವರ್ಕ್ ಲಾಕ್ ಆಗಿದೆ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 65b0409..b6fd676 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກແບບດ່ວນ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກແບບຊ້າ"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ຈຳກັດການສາກໄຟຊົ່ວຄາວ"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ຈຳກັດການສາກໄຟຊົ່ວຄາວແລ້ວ"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"ເຊື່ອມຕໍ່ສາຍສາກຂອງທ່ານ."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ເຄືອຂ່າຍຖືກລັອກ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 110b711..b4f709d 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэж байна"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Хурдан цэнэглэж байна"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Удаан цэнэглэж байна"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэхийг түр зуур хязгаарласан"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэхийг түр хязгаарласан"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Цэнэглэгчээ холбоно уу."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Түгжээг тайлах бол цэсийг дарна уу."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сүлжээ түгжигдсэн"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 82579d4..6092cc7 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan cepat"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan perlahan"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengecasan terhad buat sementara waktu"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengecasan terhad sementara"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Sambungkan pengecas anda."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rangkaian dikunci"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 371d993..bb388ea 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • polnjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • hitro polnjenje"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • počasno polnjenje"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Začasno omejeno polnjenje"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Polnjenje začasno omejeno"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Priključite napajalnik."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Če želite odkleniti, pritisnite meni."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string>
diff --git a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml
similarity index 66%
rename from packages/SystemUI/res/values-h560dp-xhdpi/config.xml
rename to packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml
index cf2017f..1a52e93 100644
--- a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2014 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,11 +12,10 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT 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.
   -->
-<resources>
-    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
-     card. -->
-    <integer name="keyguard_max_notification_count">3</integer>
-</resources>
 
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use the smaller PIN pad keys if we have the screen space to support it. -->
+    <string name="num_pad_key_ratio">1.0</string>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index adec7fe..ef36fdd 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜாகிறது"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • வேகமாகச் சார்ஜாகிறது"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • மெதுவாகச் சார்ஜாகிறது"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜாவது தற்காலிகமாக வரம்பிடப்பட்டுள்ளது"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜிங் தற்காலிகமாக வரம்பிடப்பட்டுள்ளது"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"சார்ஜரை இணைக்கவும்."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"அன்லாக் செய்ய மெனுவை அழுத்தவும்."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"நெட்வொர்க் பூட்டப்பட்டது"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 03bb5cc..f9544af 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -40,7 +40,7 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ఛార్జింగ్ తాత్కాలికంగా పరిమితం చేయబడింది"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"మీ ఛార్జర్‌ను కనెక్ట్ చేయండి."</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"అన్‌లాక్ చేయడానికి మెనుని నొక్కండి."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"అన్‌లాక్ చేయడానికి మెనూను నొక్కండి."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"నెట్‌వర్క్ లాక్ చేయబడింది"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM కార్డ్ లేదు"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM కార్డ్‌ని చొప్పించండి."</string>
@@ -83,8 +83,8 @@
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK కోడ్ అనేది 8 లేదా అంతకంటే ఎక్కువ సంఖ్యలు ఉండాలి."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. ఎక్కువసార్లు ప్రయత్నించడం వలన SIM శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"నమూనాని చాలా ఎక్కువసార్లు గీసారు"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM పిన్ కోడ్ తప్పు, ఇప్పుడు మీ డివైజ్‌ను అన్‌లాక్ చేయాలంటే, మీరు తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించాలి."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 3c3972c..be10a50 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc nhanh"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc chậm"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Khả năng sạc tạm thời bị hạn chế"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Chức năng sạc tạm thời bị hạn chế"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"Kết nối bộ sạc của bạn."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Nhấn vào Menu để mở khóa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index d950d40..621fe49 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 快速充電中"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 慢速充電中"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電功能暫時受到限制"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 已暫時限制充電"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"請連接充電器。"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按選單鍵解鎖。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"網路已鎖定"</string>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index ea769c6..871b1c4 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -62,8 +62,8 @@
         <item name="android:src">@drawable/ic_backspace_24dp</item>
     </style>
     <style name="NumPadKey.Enter">
-      <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
-      <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
+        <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
+        <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
     </style>
     <style name="Widget.TextView.NumPadKey.Klondike"
            parent="@android:style/Widget.DeviceDefault.TextView">
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/color/docked_divider_background.xml b/packages/SystemUI/res/color/docked_divider_background.xml
new file mode 100644
index 0000000..85ede9a
--- /dev/null
+++ b/packages/SystemUI/res/color/docked_divider_background.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+</selector>
diff --git a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml b/packages/SystemUI/res/color/prv_color_surface.xml
similarity index 65%
copy from packages/SystemUI/res/values-h560dp-xhdpi/config.xml
copy to packages/SystemUI/res/color/prv_color_surface.xml
index cf2017f..b9d016c 100644
--- a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml
+++ b/packages/SystemUI/res/color/prv_color_surface.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2014 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,11 +12,9 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT 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.
   -->
-<resources>
-    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
-     card. -->
-    <integer name="keyguard_max_notification_count">3</integer>
-</resources>
-
+<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?androidprv:attr/colorSurface" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml b/packages/SystemUI/res/color/prv_text_color_on_accent.xml
similarity index 64%
copy from packages/SystemUI/res/values-h560dp-xhdpi/config.xml
copy to packages/SystemUI/res/color/prv_text_color_on_accent.xml
index cf2017f..9f44aca 100644
--- a/packages/SystemUI/res/values-h560dp-xhdpi/config.xml
+++ b/packages/SystemUI/res/color/prv_text_color_on_accent.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2014 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,11 +12,9 @@
   ~ distributed under the License is distributed on an "AS IS" BASIS,
   ~ WITHOUT 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.
   -->
-<resources>
-    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
-     card. -->
-    <integer name="keyguard_max_notification_count">3</integer>
-</resources>
-
+<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?androidprv:attr/textColorOnAccent" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_state_off.xml b/packages/SystemUI/res/color/settingslib_state_off.xml
new file mode 100644
index 0000000..e821825
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_state_off.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_state_on.xml b/packages/SystemUI/res/color/settingslib_state_on.xml
new file mode 100644
index 0000000..6d2133c
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_state_on.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentPrimary"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_track_off.xml b/packages/SystemUI/res/color/settingslib_track_off.xml
new file mode 100644
index 0000000..21d1dcc
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_track_off.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentSecondary"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_track_on.xml b/packages/SystemUI/res/color/settingslib_track_on.xml
new file mode 100644
index 0000000..ba7848a
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_track_on.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
index 33263a9..0ae5dc7 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
@@ -1,201 +1,142 @@
-<?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
-  -->
+<?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.
+-->
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt">
+                 xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
-        <vector
-            android:width="60dp"
-            android:height="60dp"
-            android:viewportHeight="60"
-            android:viewportWidth="60">
+        <vector android:height="60dp" android:width="60dp" android:viewportHeight="60"
+                android:viewportWidth="60">
             <group android:name="_R_G">
-                <group
-                    android:name="_R_G_L_1_G_N_4_T_0"
-                    android:translateX="30"
-                    android:translateY="30">
-                    <group
-                        android:name="_R_G_L_1_G"
-                        android:pivotX="114"
-                        android:pivotY="114"
-                        android:scaleX="0.42200000000000004"
-                        android:scaleY="0.42200000000000004"
-                        android:translateX="-114"
-                        android:translateY="-114">
-                        <path
-                            android:name="_R_G_L_1_G_D_0_P_0"
-                            android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="0"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_1_P_0"
-                            android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="0"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_2_P_0"
-                            android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="0"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_3_P_0"
-                            android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="0"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_4_P_0"
-                            android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="0"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
+                <group android:name="_R_G_L_1_G" android:translateX="-0.05000000000000071">
+                    <group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30"
+                           android:translateY="38.75" android:scaleX="1" android:scaleY="1">
+                        <path android:name="_R_G_L_1_G_D_0_P_0"
+                              android:fillColor="@color/biometric_dialog_error"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/>
                     </group>
+                    <group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30"
+                           android:translateY="25" android:pivotX="0.002" android:pivotY="7.488"
+                           android:scaleX="1" android:scaleY="1">
+                        <path android:name="_R_G_L_1_G_D_1_P_0"
+                              android:fillColor="@color/biometric_dialog_error"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/>
+                    </group>
+                    <path android:name="_R_G_L_1_G_D_2_P_0"
+                          android:strokeColor="@color/biometric_dialog_error"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2.5" android:strokeAlpha="1"
+                          android:trimPathStart="0" android:trimPathEnd="1"
+                          android:trimPathOffset="0"
+                          android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "/>
                 </group>
-                <group
-                    android:name="_R_G_L_0_G_N_4_T_0"
-                    android:translateX="30"
-                    android:translateY="30">
-                    <group
-                        android:name="_R_G_L_0_G"
-                        android:translateX="-30.05"
-                        android:translateY="-30">
-                        <group
-                            android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
-                            android:scaleX="1"
-                            android:scaleY="1"
-                            android:translateX="30"
-                            android:translateY="38.75">
-                            <path
-                                android:name="_R_G_L_0_G_D_0_P_0"
-                                android:fillAlpha="1"
-                                android:fillColor="@color/biometric_dialog_error"
-                                android:fillType="nonZero"
-                                android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
-                        </group>
-                        <group
-                            android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
-                            android:pivotX="0.002"
-                            android:pivotY="7.488"
-                            android:scaleX="1"
-                            android:scaleY="1"
-                            android:translateX="30"
-                            android:translateY="25">
-                            <path
-                                android:name="_R_G_L_0_G_D_1_P_0"
-                                android:fillAlpha="1"
-                                android:fillColor="@color/biometric_dialog_error"
-                                android:fillType="nonZero"
-                                android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
-                        </group>
-                        <path
-                            android:name="_R_G_L_0_G_D_2_P_0"
-                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_error"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="2.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                    </group>
+                <group android:name="_R_G_L_0_G" android:translateX="-10.325"
+                       android:translateY="-10.25">
+                    <path android:name="_R_G_L_0_G_D_0_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="0" android:trimPathOffset="0"
+                          android:pathData=" M31.41 48.43 C30.78,46.69 30.78,44.91 30.78,44.91 C30.78,40.09 34.88,36.16 40.32,36.16 C45.77,36.16 49.87,40.09 49.87,44.91 C49.87,44.91 49.87,45.17 49.87,45.17 C49.87,46.97 48.41,48.43 46.61,48.43 C45.28,48.43 44.09,47.63 43.6,46.39 C43.6,46.39 42.51,43.66 42.51,43.66 C42.02,42.42 40.82,41.61 39.49,41.61 C37.69,41.61 36.23,43.07 36.23,44.87 C36.23,47.12 37.26,49.26 39.02,50.67 C39.02,50.67 39.64,51.16 39.64,51.16 "/>
+                    <path android:name="_R_G_L_0_G_D_1_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="0" android:trimPathOffset="0"
+                          android:pathData=" M32.14 27.3 C34.5,26 37.31,25.25 40.33,25.25 C43.34,25.25 46.15,26 48.51,27.3 "/>
+                    <path android:name="_R_G_L_0_G_D_2_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="0" android:trimPathOffset="0"
+                          android:pathData=" M29.42 36.16 C31.35,32.94 35.51,30.71 40.33,30.71 C45.14,30.71 49.3,32.94 51.23,36.16 "/>
+                    <path android:name="_R_G_L_0_G_D_3_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="0" android:trimPathOffset="0"
+                          android:pathData=" M47.14 52.52 C45.33,54.21 42.94,55.25 40.33,55.25 C37.71,55.25 35.32,54.21 33.51,52.52 "/>
                 </group>
             </group>
-            <group android:name="time_group" />
+            <group android:name="time_group"/>
         </vector>
     </aapt:attr>
-    <target android:name="_R_G_L_1_G_D_0_P_0">
+    <target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="83"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="scaleX" android:duration="67"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="1.1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="83"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="scaleY" android:duration="67"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="1.1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="100"
+                                android:startOffset="67" android:valueFrom="1.1" android:valueTo="0"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="100"
+                                android:startOffset="67" android:valueFrom="1.1" android:valueTo="0"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G_D_1_P_0">
+    <target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="83"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="scaleX" android:duration="67"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="83"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="scaleY" android:duration="67"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="1.1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="100"
+                                android:startOffset="67" android:valueFrom="1" android:valueTo="1"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="100"
+                                android:startOffset="67" android:valueFrom="1.1" android:valueTo="0"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -204,182 +145,58 @@
     <target android:name="_R_G_L_1_G_D_2_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="83"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="67"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="83"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="133"
+                                android:startOffset="67" android:valueFrom="1" android:valueTo="0"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G_D_3_P_0">
+    <target android:name="_R_G_L_0_G_D_0_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="83"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="83"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+                                android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G_D_4_P_0">
+    <target android:name="_R_G_L_0_G_D_1_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="83"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="83"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+                                android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleX"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1.1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1.1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleX"
-                    android:startOffset="67"
-                    android:valueFrom="1.1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleY"
-                    android:startOffset="67"
-                    android:valueFrom="1.1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleX"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1.1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleX"
-                    android:startOffset="67"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleY"
-                    android:startOffset="67"
-                    android:valueFrom="1.1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -388,26 +205,38 @@
     <target android:name="_R_G_L_0_G_D_2_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
-                <objectAnimator
-                    android:duration="133"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="67"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+                                android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+                                android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -416,14 +245,10 @@
     <target android:name="time_group">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="350"
-                    android:propertyName="translateX"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType" />
+                <objectAnimator android:propertyName="translateX" android:duration="417"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
             </set>
         </aapt:attr>
     </target>
-</animated-vector>
\ No newline at end of file
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
index b899828..fc2c7d0 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
@@ -1,179 +1,170 @@
-<?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
-  -->
+<?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.
+-->
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt">
+                 xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
-        <vector
-            android:width="60dp"
-            android:height="60dp"
-            android:viewportHeight="60"
-            android:viewportWidth="60">
+        <vector android:height="60dp" android:width="60dp" android:viewportHeight="60"
+                android:viewportWidth="60">
             <group android:name="_R_G">
-                <group
-                    android:name="_R_G_L_1_G_N_4_T_0"
-                    android:translateX="30"
-                    android:translateY="30">
-                    <group
-                        android:name="_R_G_L_1_G"
-                        android:pivotX="114"
-                        android:pivotY="114"
-                        android:scaleX="0.42244"
-                        android:scaleY="0.42244"
-                        android:translateX="-114"
-                        android:translateY="-114">
-                        <path
-                            android:name="_R_G_L_1_G_D_0_P_0"
-                            android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_1_P_0"
-                            android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_2_P_0"
-                            android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_3_P_0"
-                            android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
-                        <path
-                            android:name="_R_G_L_1_G_D_4_P_0"
-                            android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_accent"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="5.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="0" />
+                <group android:name="_R_G_L_1_G" android:translateX="-0.05000000000000071">
+                    <group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30"
+                           android:translateY="38.75" android:scaleX="0" android:scaleY="0">
+                        <path android:name="_R_G_L_1_G_D_0_P_0"
+                              android:fillColor="@color/biometric_dialog_error"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/>
                     </group>
+                    <group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30"
+                           android:translateY="25" android:pivotX="0.002" android:pivotY="7.488"
+                           android:scaleX="1" android:scaleY="0">
+                        <path android:name="_R_G_L_1_G_D_1_P_0"
+                              android:fillColor="@color/biometric_dialog_error"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/>
+                    </group>
+                    <path android:name="_R_G_L_1_G_D_2_P_0"
+                          android:strokeColor="@color/biometric_dialog_error"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2.5" android:strokeAlpha="1"
+                          android:trimPathStart="1" android:trimPathEnd="1"
+                          android:trimPathOffset="0"
+                          android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "/>
                 </group>
-                <group
-                    android:name="_R_G_L_0_G_N_4_T_0"
-                    android:translateX="30"
-                    android:translateY="30">
-                    <group
-                        android:name="_R_G_L_0_G"
-                        android:translateX="-30.05"
-                        android:translateY="-30">
-                        <group
-                            android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
-                            android:scaleX="0"
-                            android:scaleY="0"
-                            android:translateX="30"
-                            android:translateY="38.75">
-                            <path
-                                android:name="_R_G_L_0_G_D_0_P_0"
-                                android:fillAlpha="1"
-                                android:fillColor="@color/biometric_dialog_error"
-                                android:fillType="nonZero"
-                                android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
-                        </group>
-                        <group
-                            android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
-                            android:pivotX="0.002"
-                            android:pivotY="7.488"
-                            android:scaleX="1"
-                            android:scaleY="0"
-                            android:translateX="30"
-                            android:translateY="25">
-                            <path
-                                android:name="_R_G_L_0_G_D_1_P_0"
-                                android:fillAlpha="1"
-                                android:fillColor="@color/biometric_dialog_error"
-                                android:fillType="nonZero"
-                                android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
-                        </group>
-                        <path
-                            android:name="_R_G_L_0_G_D_2_P_0"
-                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
-                            android:strokeAlpha="1"
-                            android:strokeColor="@color/biometric_dialog_error"
-                            android:strokeLineCap="round"
-                            android:strokeLineJoin="round"
-                            android:strokeWidth="2.5"
-                            android:trimPathEnd="1"
-                            android:trimPathOffset="0"
-                            android:trimPathStart="1" />
-                    </group>
+                <group android:name="_R_G_L_0_G" android:translateX="-10.325"
+                       android:translateY="-10.25">
+                    <path android:name="_R_G_L_0_G_D_0_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="1" android:trimPathOffset="0"
+                          android:pathData=" M31.41 48.43 C30.78,46.69 30.78,44.91 30.78,44.91 C30.78,40.09 34.88,36.16 40.32,36.16 C45.77,36.16 49.87,40.09 49.87,44.91 C49.87,44.91 49.87,45.17 49.87,45.17 C49.87,46.97 48.41,48.43 46.61,48.43 C45.28,48.43 44.09,47.63 43.6,46.39 C43.6,46.39 42.51,43.66 42.51,43.66 C42.02,42.42 40.82,41.61 39.49,41.61 C37.69,41.61 36.23,43.07 36.23,44.87 C36.23,47.12 37.26,49.26 39.02,50.67 C39.02,50.67 39.64,51.16 39.64,51.16 "/>
+                    <path android:name="_R_G_L_0_G_D_1_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="1" android:trimPathOffset="0"
+                          android:pathData=" M32.14 27.3 C34.5,26 37.31,25.25 40.33,25.25 C43.34,25.25 46.15,26 48.51,27.3 "/>
+                    <path android:name="_R_G_L_0_G_D_2_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="1" android:trimPathOffset="0"
+                          android:pathData=" M29.42 36.16 C31.35,32.94 35.51,30.71 40.33,30.71 C45.14,30.71 49.3,32.94 51.23,36.16 "/>
+                    <path android:name="_R_G_L_0_G_D_3_P_0"
+                          android:strokeColor="@color/biometric_dialog_accent"
+                          android:strokeLineCap="round" android:strokeLineJoin="round"
+                          android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+                          android:trimPathEnd="1" android:trimPathOffset="0"
+                          android:pathData=" M47.14 52.52 C45.33,54.21 42.94,55.25 40.33,55.25 C37.71,55.25 35.32,54.21 33.51,52.52 "/>
                 </group>
             </group>
-            <group android:name="time_group" />
+            <group android:name="time_group"/>
         </vector>
     </aapt:attr>
-    <target android:name="_R_G_L_1_G_D_0_P_0">
+    <target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="scaleX" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="100"
+                                android:startOffset="167" android:valueFrom="0"
+                                android:valueTo="1.1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="100"
+                                android:startOffset="167" android:valueFrom="0"
+                                android:valueTo="1.1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="67"
+                                android:startOffset="267" android:valueFrom="1.1"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="67"
+                                android:startOffset="267" android:valueFrom="1.1"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G_D_1_P_0">
+    <target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="scaleX" android:duration="167"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="100"
+                                android:startOffset="167" android:valueFrom="1" android:valueTo="1"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="100"
+                                android:startOffset="167" android:valueFrom="0"
+                                android:valueTo="1.1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="67"
+                                android:startOffset="267" android:valueFrom="1" android:valueTo="1"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="67"
+                                android:startOffset="267" android:valueFrom="1.1"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -182,193 +173,37 @@
     <target android:name="_R_G_L_1_G_D_2_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathStart" android:duration="267"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G_D_3_P_0">
+    <target android:name="_R_G_L_0_G_D_0_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G_D_4_P_0">
+    <target android:name="_R_G_L_0_G_D_1_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="scaleX"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleX"
-                    android:startOffset="167"
-                    android:valueFrom="0"
-                    android:valueTo="1.1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleY"
-                    android:startOffset="167"
-                    android:valueFrom="0"
-                    android:valueTo="1.1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleX"
-                    android:startOffset="267"
-                    android:valueFrom="1.1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleY"
-                    android:startOffset="267"
-                    android:valueFrom="1.1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="scaleX"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleX"
-                    android:startOffset="167"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="scaleY"
-                    android:startOffset="167"
-                    android:valueFrom="0"
-                    android:valueTo="1.1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleX"
-                    android:startOffset="267"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="scaleY"
-                    android:startOffset="267"
-                    android:valueFrom="1.1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -377,15 +212,24 @@
     <target android:name="_R_G_L_0_G_D_2_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="267"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
+                <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -394,14 +238,10 @@
     <target android:name="time_group">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
-                <objectAnimator
-                    android:duration="350"
-                    android:propertyName="translateX"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType" />
+                <objectAnimator android:propertyName="translateX" android:duration="350"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
             </set>
         </aapt:attr>
     </target>
-</animated-vector>
\ No newline at end of file
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_media_home_devices.xml b/packages/SystemUI/res/drawable/ic_media_home_devices.xml
new file mode 100644
index 0000000..886c64d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_media_home_devices.xml
@@ -0,0 +1,16 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M20,4H4c-1.1,0 -2,0.9 -2,2v11c0,1.1 0.9,2 2,2h4v2h3v-4H4V6h16v1h2V6c0,-1.1 -0.9,-2 -2,-2z"/>
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M17.5,16.5m-2.33,0a2.33,2.33 0,1 1,4.66 0a2.33,2.33 0,1 1,-4.66 0"/>
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M21,8h-7c-0.55,0 -1,0.45 -1,1v11c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1L22,9c0,-0.55 -0.45,-1 -1,-1zM17.5,9c0.83,0 1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5 -1.5,-0.67 -1.5,-1.5 0.67,-1.5 1.5,-1.5zM17.5,20c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_unlock.xml b/packages/SystemUI/res/drawable/ic_unlock.xml
index c3b3469..46023e6 100644
--- a/packages/SystemUI/res/drawable/ic_unlock.xml
+++ b/packages/SystemUI/res/drawable/ic_unlock.xml
@@ -21,7 +21,7 @@
             android:strokeColor="#FF000000"
             android:strokeLineCap="round"
             android:strokeLineJoin="round"
-            android:strokeWidth="2.5"
+            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">
@@ -29,7 +29,7 @@
             android:strokeColor="#FF000000"
             android:strokeLineCap="round"
             android:strokeLineJoin="round"
-            android:strokeWidth="2.5"
+            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">
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index 1535e72..3a08a71 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -22,11 +22,12 @@
     android:color="?android:attr/textColorPrimary">
   <item>
     <shape
-        android:shape="oval">
+        android:shape="rectangle">
       <solid android:color="?androidprv:attr/colorSurface"/>
       <size
           android:width="@dimen/keyguard_affordance_width"
           android:height="@dimen/keyguard_affordance_height"/>
+      <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/>
     </shape>
   </item>
 </ripple>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
new file mode 100644
index 0000000..1a128df
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:insetTop="@dimen/qs_dialog_button_vertical_inset"
+       android:insetBottom="@dimen/qs_dialog_button_vertical_inset">
+    <ripple android:color="?android:attr/colorControlHighlight">
+        <item android:id="@android:id/mask">
+            <shape android:shape="rectangle">
+                <solid android:color="@android:color/white"/>
+                <corners android:radius="?android:attr/buttonCornerRadius"/>
+            </shape>
+        </item>
+        <item>
+            <shape android:shape="rectangle">
+                <corners android:radius="?android:attr/buttonCornerRadius"/>
+                <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+                <padding android:left="@dimen/qs_dialog_button_horizontal_padding"
+                         android:top="@dimen/qs_dialog_button_vertical_padding"
+                         android:right="@dimen/qs_dialog_button_horizontal_padding"
+                         android:bottom="@dimen/qs_dialog_button_vertical_padding"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
new file mode 100644
index 0000000..467c20f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
@@ -0,0 +1,42 @@
+<?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.
+  -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:insetTop="@dimen/qs_dialog_button_vertical_inset"
+       android:insetBottom="@dimen/qs_dialog_button_vertical_inset">
+    <ripple android:color="?android:attr/colorControlHighlight">
+        <item android:id="@android:id/mask">
+            <shape android:shape="rectangle">
+                <solid android:color="@android:color/white"/>
+                <corners android:radius="?android:attr/buttonCornerRadius"/>
+            </shape>
+        </item>
+        <item>
+            <shape android:shape="rectangle">
+                <corners android:radius="?android:attr/buttonCornerRadius"/>
+                <solid android:color="@android:color/transparent"/>
+                <stroke android:color="?androidprv:attr/colorAccentPrimary"
+                        android:width="1dp"
+                />
+                <padding android:left="@dimen/qs_dialog_button_horizontal_padding"
+                         android:top="@dimen/qs_dialog_button_vertical_padding"
+                         android:right="@dimen/qs_dialog_button_horizontal_padding"
+                         android:bottom="@dimen/qs_dialog_button_vertical_padding"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
diff --git a/packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml b/packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml
new file mode 100644
index 0000000..5cc8d6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml
@@ -0,0 +1,16 @@
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- Overlay this resource to change rounded_corners_bottom -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/rounded_secondary"/>
diff --git a/packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml b/packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml
new file mode 100644
index 0000000..724e3ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml
@@ -0,0 +1,16 @@
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- Overlay this resource to change rounded_corners_top -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/rounded_secondary"/>
diff --git a/packages/SystemUI/res/drawable/rounded_secondary.xml b/packages/SystemUI/res/drawable/rounded_secondary.xml
new file mode 100644
index 0000000..eb72fa1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_secondary.xml
@@ -0,0 +1,24 @@
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="8dp"
+    android:height="8dp"
+    android:viewportWidth="8"
+    android:viewportHeight="8">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M8,0H0v8C0,3.6,3.6,0,8,0z" />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_off.xml b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml
index 8b69ad1..87d4aea 100644
--- a/packages/SystemUI/res/drawable/settingslib_thumb_off.xml
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml
@@ -18,8 +18,6 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:top="@dimen/settingslib_switch_thumb_margin"
-        android:left="@dimen/settingslib_switch_thumb_margin"
-        android:right="@dimen/settingslib_switch_thumb_margin"
         android:bottom="@dimen/settingslib_switch_thumb_margin">
         <shape android:shape="oval">
             <size
diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
index 0f27fc2..5566ea3 100644
--- a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
+++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml
@@ -18,8 +18,6 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:top="@dimen/settingslib_switch_thumb_margin"
-        android:left="@dimen/settingslib_switch_thumb_margin"
-        android:right="@dimen/settingslib_switch_thumb_margin"
         android:bottom="@dimen/settingslib_switch_thumb_margin">
         <shape android:shape="oval">
             <size
diff --git a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
index 4d79a6e..3a09284 100644
--- a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
+++ b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
@@ -19,6 +19,8 @@
     android:shape="rectangle"
     android:width="@dimen/settingslib_switch_track_width"
     android:height="@dimen/settingslib_switch_track_height">
+    <padding android:left="@dimen/settingslib_switch_thumb_margin"
+             android:right="@dimen/settingslib_switch_thumb_margin"/>
     <solid android:color="@color/settingslib_track_off_color"/>
     <corners android:radius="@dimen/settingslib_switch_track_radius"/>
 </shape>
diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
index c12d012..1d9dacd 100644
--- a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
+++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml
@@ -19,6 +19,8 @@
     android:shape="rectangle"
     android:width="@dimen/settingslib_switch_track_width"
     android:height="@dimen/settingslib_switch_track_height">
+    <padding android:left="@dimen/settingslib_switch_thumb_margin"
+             android:right="@dimen/settingslib_switch_thumb_margin"/>
     <solid android:color="@color/settingslib_track_on_color"/>
     <corners android:radius="@dimen/settingslib_switch_track_radius"/>
 </shape>
diff --git a/packages/SystemUI/res/layout/communal_host_view.xml b/packages/SystemUI/res/layout/communal_host_view.xml
index 4406a46..cd9c260 100644
--- a/packages/SystemUI/res/layout/communal_host_view.xml
+++ b/packages/SystemUI/res/layout/communal_host_view.xml
@@ -18,13 +18,6 @@
 <!-- This is a view that shows general status information in Keyguard. -->
 <com.android.systemui.communal.CommunalHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     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
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_grid_lite.xml b/packages/SystemUI/res/layout/global_actions_grid_lite.xml
index 2430eec..5588fd3 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_lite.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_lite.xml
@@ -13,13 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
+<androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/global_actions_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
     android:gravity="center"
     android:layout_gravity="center">
   <com.android.systemui.globalactions.GlobalActionsLayoutLite
@@ -29,8 +28,11 @@
       android:orientation="vertical"
       android:clipChildren="false"
       android:clipToPadding="false"
-      android:background="@drawable/global_actions_lite_background"
-      android:padding="@dimen/global_actions_lite_padding">
+      app:layout_constraintBottom_toBottomOf="parent"
+      app:layout_constraintTop_toTopOf="parent"
+      app:layout_constraintStart_toStartOf="parent"
+      app:layout_constraintEnd_toEndOf="parent"
+      android:layout_weight="1">
     <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -38,6 +40,8 @@
         android:gravity="center"
         android:translationZ="@dimen/global_actions_translate"
         android:orientation="horizontal"
+        android:background="@drawable/global_actions_lite_background"
+        android:padding="@dimen/global_actions_lite_padding"
         android:layoutDirection="ltr">
       <androidx.constraintlayout.helper.widget.Flow
           android:id="@+id/list_flow"
@@ -53,4 +57,4 @@
           app:flow_horizontalStyle="packed"/>
     </androidx.constraintlayout.widget.ConstraintLayout>
   </com.android.systemui.globalactions.GlobalActionsLayoutLite>
-</LinearLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_toast.xml b/packages/SystemUI/res/layout/global_actions_toast.xml
new file mode 100644
index 0000000..1f08996
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_toast.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.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center|bottom"
+    android:gravity="center"
+    android:layout_marginBottom="@dimen/global_actions_info_margin"
+    app:layout_constraintBottom_toBottomOf="parent"
+    app:layout_constraintStart_toStartOf="parent"
+    app:layout_constraintEnd_toEndOf="parent"
+    app:layout_constraintWidth_max="382dp"
+    android:layout_weight="0"
+    android:background="@drawable/global_actions_lite_background"
+    android:theme="@style/Theme.SystemUI.QuickSettings"
+    android:paddingTop="14dp"
+    android:paddingBottom="14dp"
+    android:paddingStart="20dp"
+    android:paddingEnd="20dp"
+    android:orientation="horizontal">
+    <TextView
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textSize="14sp"
+        android:textColor="?android:attr/textColorSecondary"
+        android:text="@string/global_action_smart_lock_disabled" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index e4a9694..6a9254c 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -36,7 +36,6 @@
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
-        android:layout_marginBottom="@dimen/screenshot_action_container_offset_y"
         android:paddingEnd="@dimen/screenshot_action_container_padding_right"
         android:paddingVertical="@dimen/screenshot_action_container_padding_vertical"
         android:elevation="1dp"
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index f23085a..b841419 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -19,18 +19,18 @@
     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"
+    android:layout_width="@dimen/internet_dialog_list_max_width"
+    android:layout_height="@dimen/internet_dialog_list_max_height"
     android:background="@drawable/internet_dialog_rounded_top_corner_background"
     android:orientation="vertical">
 
     <LinearLayout
         android:layout_width="match_parent"
+        android:layout_height="wrap_content"
         style="@style/Widget.SliceView.Panel"
         android:gravity="center_vertical|center_horizontal"
         android:layout_marginTop="24dp"
-        android:layout_marginBottom="16dp"
-        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
         android:orientation="vertical">
 
         <TextView
@@ -54,21 +54,28 @@
             android:textSize="14sp"/>
     </LinearLayout>
 
-    <View
-        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="340dp"
+    <LinearLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:visibility="gone"
-        style="@style/TrimmedHorizontalProgressBar"/>
+        android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
+        android:orientation="vertical">
+
+        <View
+            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="340dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:visibility="gone"
+            style="@style/TrimmedHorizontalProgressBar"/>
+    </LinearLayout>
 
     <androidx.core.widget.NestedScrollView
         android:id="@+id/scroll_view"
@@ -94,9 +101,8 @@
                     android:background="?android:attr/selectableItemBackground"
                     android:layout_gravity="center_vertical|start"
                     android:orientation="horizontal"
-                    android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginStart="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginTop="16dp"
+                    android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
                     android:paddingStart="22dp"
                     android:paddingEnd="22dp">
 
@@ -124,38 +130,39 @@
                         <TextView
                             android:id="@+id/mobile_title"
                             android:textDirection="locale"
-                            android:layout_marginStart="16dp"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                            android:layout_marginEnd="7dp"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_gravity="center_vertical|start"
                             android:ellipsize="end"
-                            android:maxLines="1"
                             android:textColor="?android:attr/textColorPrimary"
                             android:textSize="16sp"
                             android:fontFamily="google-sans"/>
                         <TextView
                             android:id="@+id/mobile_summary"
                             android:textDirection="locale"
-                            android:layout_marginStart="16dp"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                            android:layout_marginEnd="34dp"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_gravity="center_vertical|start"
                             android:ellipsize="end"
-                            android:maxLines="1"
                             android:textColor="?android:attr/textColorTertiary"
                             android:textSize="14sp"
                             android:fontFamily="google-sans"/>
                     </LinearLayout>
 
                     <FrameLayout
-                        android:layout_width="48dp"
+                        android:layout_width="@dimen/settingslib_switch_track_width"
                         android:layout_height="48dp"
                         android:layout_gravity="end|center_vertical">
                         <Switch
                             android:id="@+id/mobile_toggle"
+                            android:switchMinWidth="@dimen/settingslib_switch_track_width"
                             android:layout_gravity="center"
-                            android:layout_width="48dp"
-                            android:layout_height="wrap_content"
+                            android:layout_width="@dimen/settingslib_switch_track_width"
+                            android:layout_height="@dimen/settingslib_switch_track_height"
                             android:track="@drawable/settingslib_track_selector"
                             android:thumb="@drawable/settingslib_thumb_selector"
                             android:theme="@style/MainSwitch.Settingslib"/>
@@ -172,8 +179,8 @@
                     android:background="?android:attr/selectableItemBackground"
                     android:gravity="center"
                     android:orientation="horizontal"
-                    android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginStart="@dimen/settingslib_switchbar_margin"
+                    android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
                     android:paddingStart="22dp"
                     android:paddingEnd="22dp">
 
@@ -184,6 +191,7 @@
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent">
                         <TextView
+                            android:id="@+id/wifi_toggle_title"
                             android:text="@string/turn_on_wifi"
                             android:textDirection="locale"
                             android:layout_width="wrap_content"
@@ -195,15 +203,16 @@
                     </FrameLayout>
 
                     <FrameLayout
-                        android:layout_width="48dp"
+                        android:layout_width="@dimen/settingslib_switch_track_width"
                         android:layout_height="48dp"
                         android:layout_marginTop="10dp"
                         android:layout_marginBottom="10dp">
                         <Switch
                             android:id="@+id/wifi_toggle"
+                            android:switchMinWidth="@dimen/settingslib_switch_track_width"
                             android:layout_gravity="center"
-                            android:layout_width="48dp"
-                            android:layout_height="wrap_content"
+                            android:layout_width="@dimen/settingslib_switch_track_width"
+                            android:layout_height="@dimen/settingslib_switch_track_height"
                             android:track="@drawable/settingslib_track_selector"
                             android:thumb="@drawable/settingslib_thumb_selector"
                             android:theme="@style/MainSwitch.Settingslib"/>
@@ -221,10 +230,10 @@
                     android:visibility="gone"
                     android:background="?android:attr/selectableItemBackground"
                     android:orientation="horizontal"
-                    android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginStart="@dimen/settingslib_switchbar_margin"
-                    android:paddingStart="22dp"
-                    android:paddingEnd="22dp">
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+                    android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+                    android:paddingStart="20dp"
+                    android:paddingEnd="24dp">
 
                     <FrameLayout
                         android:layout_width="24dp"
@@ -239,12 +248,13 @@
                     </FrameLayout>
 
                     <LinearLayout
-                        android:layout_weight="3"
                         android:id="@+id/wifi_connected_list"
                         android:orientation="vertical"
                         android:clickable="false"
                         android:layout_width="wrap_content"
                         android:layout_height="72dp"
+                        android:layout_marginEnd="30dp"
+                        android:layout_weight="1"
                         android:gravity="start|center_vertical">
                         <TextView
                             android:id="@+id/wifi_connected_title"
@@ -252,9 +262,8 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_gravity="center_vertical|start"
-                            android:layout_marginStart="16dp"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
                             android:ellipsize="end"
-                            android:maxLines="1"
                             android:textColor="?android:attr/textColorPrimary"
                             android:textSize="14sp"
                             android:fontFamily="google-sans"/>
@@ -264,9 +273,8 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_gravity="center_vertical|start"
-                            android:layout_marginStart="16dp"
+                            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
                             android:ellipsize="end"
-                            android:maxLines="1"
                             android:textColor="?android:attr/textColorTertiary"
                             android:textSize="14sp"
                             android:fontFamily="google-sans"/>
@@ -275,14 +283,14 @@
                     <FrameLayout
                         android:layout_width="24dp"
                         android:layout_height="match_parent"
-                        android:layout_marginEnd="5dp"
                         android:clickable="false"
+                        android:layout_gravity="end|center_vertical"
                         android:gravity="center">
                         <ImageView
                             android:id="@+id/wifi_settings_icon"
                             android:src="@drawable/ic_settings_24dp"
                             android:layout_width="24dp"
-                            android:layout_gravity="center"
+                            android:layout_gravity="end|center_vertical"
                             android:layout_height="wrap_content"/>
                     </FrameLayout>
 
@@ -315,7 +323,7 @@
                     android:layout_height="24dp"
                     android:clickable="false"
                     android:layout_gravity="center_vertical|start"
-                    android:layout_marginStart="16dp">
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
                     <ImageView
                         android:id="@+id/arrow_forward"
                         android:src="@drawable/ic_arrow_forward"
@@ -329,7 +337,7 @@
                     android:clickable="false"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:layout_marginStart="16dp">
+                    android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
                     <TextView
                         android:text="@string/see_all_networks"
                         android:textDirection="locale"
@@ -343,31 +351,23 @@
 
             </LinearLayout>
 
-            <Space
-                android:id="@+id/space"
-                android:layout_width="match_parent"
-                android:layout_height="28dp"
-                android:visibility="gone"/>
-
-            <LinearLayout
+            <FrameLayout
                 android:layout_width="match_parent"
                 android:layout_height="48dp"
-                android:layout_marginBottom="25dp"
-                android:gravity="end"
-                android:orientation="horizontal">
+                android:layout_marginBottom="40dp">
                 <Button
                     style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
                     android:id="@+id/done"
-                    android:layout_width="60dp"
-                    android:layout_height="30dp"
+                    android:layout_width="67dp"
+                    android:layout_height="36dp"
                     android:layout_marginEnd="24dp"
-                    android:layout_gravity="end"
+                    android:layout_gravity="end|center_vertical"
                     android:background="@drawable/internet_dialog_footer_background"
                     android:textColor="?android:attr/textColorPrimary"
                     android:text="@string/inline_done_button"
                     android:textSize="14sp"
                     android:fontFamily="google-sans"/>
-            </LinearLayout>
+            </FrameLayout>
         </LinearLayout>
     </androidx.core.widget.NestedScrollView>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml
index 19b1ef9..05352c5 100644
--- a/packages/SystemUI/res/layout/internet_list_item.xml
+++ b/packages/SystemUI/res/layout/internet_list_item.xml
@@ -31,15 +31,14 @@
         android:focusable="true"
         android:background="?android:attr/selectableItemBackground"
         android:orientation="horizontal"
-        android:paddingStart="22dp"
-        android:paddingEnd="22dp">
-
+        android:paddingStart="20dp"
+        android:paddingEnd="40dp">
         <FrameLayout
             android:layout_width="24dp"
             android:layout_height="24dp"
             android:clickable="false"
             android:layout_gravity="center_vertical|start"
-            android:layout_marginStart="16dp">
+            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
             <ImageView
                 android:id="@+id/wifi_icon"
                 android:layout_width="wrap_content"
@@ -48,52 +47,47 @@
         </FrameLayout>
 
         <LinearLayout
-            android:layout_weight="3"
             android:id="@+id/wifi_network_layout"
             android:orientation="vertical"
             android:clickable="false"
             android:layout_width="wrap_content"
-            android:layout_height="72dp">
+            android:layout_height="72dp"
+            android:layout_weight="1"
+            android:gravity="start|center_vertical"
+            android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
             <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|start"
+                android:layout_height="20dp"
                 android:gravity="start|center_vertical"
-                android:layout_marginStart="16dp"
                 android:ellipsize="end"
-                android:maxLines="1"
                 android:textColor="?android:attr/textColorPrimary"
                 android:textSize="14sp"
-                android:fontFamily="google-sans"/>
+                android:fontFamily="google-sans"
+                android:layout_marginEnd="18dp"/>
             <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|start"
+                android:layout_height="wrap_content"
                 android:gravity="start|center_vertical"
-                android:layout_marginStart="16dp"
                 android:ellipsize="end"
-                android:maxLines="1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:textSize="14sp"
-                android:fontFamily="google-sans"/>
+                android:fontFamily="google-sans"
+                android:layout_marginEnd="18dp"/>
         </LinearLayout>
 
         <FrameLayout
             android:layout_width="24dp"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/settingslib_switchbar_padding_right"
             android:clickable="false"
-            android:gravity="center">
+            android:layout_gravity="end|center_vertical">
             <ImageView
-                android:id="@+id/wifi_locked_icon"
+                android:id="@+id/wifi_end_icon"
+                android:layout_gravity="end|center_vertical"
                 android:layout_width="wrap_content"
-                android:layout_gravity="center"
                 android:layout_height="wrap_content"/>
         </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 075473a..566cd25 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -163,18 +163,6 @@
         </LinearLayout>
     </LinearLayout>
 
-    <ImageView
-        android:id="@+id/media_seamless_fallback"
-        android:layout_width="@dimen/qs_seamless_fallback_icon_size"
-        android:layout_height="@dimen/qs_seamless_fallback_icon_size"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_center_guideline_padding"
-        android:layout_marginEnd="@dimen/qs_seamless_fallback_margin"
-        android:tint="?android:attr/textColor"
-        android:src="@drawable/ic_cast_connected"
-        android:forceHasOverlappingRendering="false" />
-
     <!-- Seek Bar -->
     <!-- As per Material Design on Biderectionality, this is forced to LTR in code -->
     <SeekBar
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 59e1a75..78655c0 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -20,9 +20,9 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/qs_detail_background"
+    android:layout_marginTop="@dimen/qs_detail_margin_top"
     android:clickable="true"
     android:orientation="vertical"
-    android:layout_marginTop="@*android:dimen/quick_qs_offset_height"
     android:paddingBottom="8dp"
     android:visibility="invisible"
     android:elevation="4dp"
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index da80633..d1ab054 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -28,7 +28,7 @@
 
     <com.android.systemui.ResizingSpace
         android:layout_width="match_parent"
-        android:layout_height="@dimen/qs_detail_margin_top" />
+        android:layout_height="@dimen/qs_detail_header_margin_top" />
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 317dbc0..e70084b 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -68,93 +68,9 @@
 
         </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/footer_actions"
+            android:id="@+id/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/qs_user_dialog_content.xml b/packages/SystemUI/res/layout/qs_user_dialog_content.xml
new file mode 100644
index 0000000..377da45
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_user_dialog_content.xml
@@ -0,0 +1,89 @@
+<?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.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="24dp"
+    android:layout_marginStart="16dp"
+    android:layout_marginEnd="16dp"
+    android:background="@drawable/qs_dialog_bg"
+>
+    <TextView
+        android:id="@+id/title"
+        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:textAlignment="center"
+        android:text="Select user"
+        android:textAppearance="@style/TextAppearance.QSDialog.Title"
+        android:layout_marginBottom="32dp"
+        sysui:layout_constraintTop_toTopOf="parent"
+        sysui:layout_constraintStart_toStartOf="parent"
+        sysui:layout_constraintEnd_toEndOf="parent"
+        sysui:layout_constraintBottom_toTopOf="@id/grid"
+        />
+
+    <com.android.systemui.qs.PseudoGridView
+        android:id="@+id/grid"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="28dp"
+        sysui:verticalSpacing="4dp"
+        sysui:horizontalSpacing="4dp"
+        sysui:fixedChildWidth="80dp"
+        sysui:layout_constraintTop_toBottomOf="@id/title"
+        sysui:layout_constraintStart_toStartOf="parent"
+        sysui:layout_constraintEnd_toEndOf="parent"
+        sysui:layout_constraintBottom_toTopOf="@id/barrier"
+    />
+
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/barrier"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        sysui:barrierDirection="top"
+        sysui:constraint_referenced_ids="settings,done"
+        />
+
+    <Button
+        android:id="@+id/settings"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:text="@string/quick_settings_more_user_settings"
+        sysui:layout_constraintTop_toBottomOf="@id/barrier"
+        sysui:layout_constraintBottom_toBottomOf="parent"
+        sysui:layout_constraintStart_toStartOf="parent"
+        sysui:layout_constraintEnd_toStartOf="@id/done"
+        sysui:layout_constraintHorizontal_chainStyle="spread_inside"
+        style="@style/Widget.QSDialog.Button.BorderButton"
+        />
+
+    <Button
+        android:id="@+id/done"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:text="@string/quick_settings_done"
+        sysui:layout_constraintTop_toBottomOf="@id/barrier"
+        sysui:layout_constraintBottom_toBottomOf="parent"
+        sysui:layout_constraintStart_toEndOf="@id/settings"
+        sysui:layout_constraintEnd_toEndOf="parent"
+        style="@style/Widget.QSDialog.Button"
+        />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index df02730..6b14c96 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -56,7 +56,18 @@
             android:clipToPadding="false"
             android:focusable="true"
             android:paddingBottom="24dp"
-            android:importantForAccessibility="yes" />
+            android:importantForAccessibility="yes">
+
+            <include
+                layout="@layout/footer_actions"
+                android:id="@+id/qqs_footer_actions"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:layout_marginStart="@dimen/qs_footer_margin"
+                android:layout_marginEnd="@dimen/qs_footer_margin"
+                />
+        </com.android.systemui.qs.QuickQSPanel>
     </RelativeLayout>
 
 </com.android.systemui.qs.QuickStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index cc44b5e..b1e8c38 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -49,6 +49,11 @@
         />
     </FrameLayout>
 
+    <!-- We want this to be centered (to align with notches). In order to do that, the following
+         has to hold (in portrait):
+         * date_container and privacy_container must have the same width and weight
+         * header_text_container must be gone
+         -->
     <android.widget.Space
         android:id="@+id/space"
         android:layout_width="0dp"
@@ -75,7 +80,7 @@
         android:layout_weight="1"
         android:gravity="center_vertical|end" >
 
-    <include layout="@layout/ongoing_privacy_chip" />
+        <include layout="@layout/ongoing_privacy_chip" />
 
     </FrameLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index d1cc01f..c122829 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -113,6 +113,8 @@
                         android:layout_height="wrap_content"
                         android:minHeight="48dp"
                         android:layout_weight="1"
+                        android:layout_gravity="fill_vertical"
+                        android:gravity="center_vertical"
                         android:text="@string/screenrecord_taps_label"
                         android:textAppearance="?android:attr/textAppearanceMedium"
                         android:fontFamily="@*android:string/config_headlineFontFamily"
diff --git a/packages/SystemUI/res/layout/smart_action_button.xml b/packages/SystemUI/res/layout/smart_action_button.xml
index 488be3a..4e5785d 100644
--- a/packages/SystemUI/res/layout/smart_action_button.xml
+++ b/packages/SystemUI/res/layout/smart_action_button.xml
@@ -29,8 +29,8 @@
         android:textSize="@dimen/smart_reply_button_font_size"
         android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
         android:textColor="@color/smart_reply_button_text"
-        android:paddingLeft="@dimen/smart_reply_button_action_padding_left"
-        android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
+        android:paddingStart="@dimen/smart_reply_button_action_padding_left"
+        android:paddingEnd="@dimen/smart_reply_button_padding_horizontal"
         android:drawablePadding="@dimen/smart_action_button_icon_padding"
         android:textStyle="normal"
         android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index ddf16e0..b24362f 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -31,7 +31,7 @@
         android:textSize="@dimen/smart_reply_button_font_size"
         android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
         android:textColor="@color/smart_reply_button_text"
-        android:paddingLeft="@dimen/smart_reply_button_padding_horizontal"
-        android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
+        android:paddingStart="@dimen/smart_reply_button_padding_horizontal"
+        android:paddingEnd="@dimen/smart_reply_button_padding_horizontal"
         android:textStyle="normal"
         android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index e37a3f0..9821fb0 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -25,6 +25,10 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@android:color/transparent">
+
+    <include layout="@layout/communal_host_view"
+             android:visibility="gone"/>
+
     <FrameLayout
         android:id="@+id/big_clock_container"
         android:layout_width="match_parent"
@@ -54,8 +58,7 @@
     <com.android.keyguard.LockIconView
         android:id="@+id/lock_icon_view"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center">
+        android:layout_height="wrap_content">
         <!-- Background protection -->
         <ImageView
             android:id="@+id/lock_icon_bg"
@@ -68,7 +71,7 @@
             android:id="@+id/lock_icon"
             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"/>
     </com.android.keyguard.LockIconView>
@@ -92,18 +95,6 @@
                  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
@@ -133,13 +124,11 @@
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
             android:layout_marginBottom="@dimen/close_handle_underlap"
+            android:importantForAccessibility="no"
             systemui:layout_constraintStart_toStartOf="parent"
             systemui:layout_constraintEnd_toEndOf="parent"
         />
 
-        <include layout="@layout/communal_host_view"
-                 android:visibility="gone"/>
-
         <include layout="@layout/ambient_indication"
             android:id="@+id/ambient_indication_container" />
 
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index bea50e8..d9a5670 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -62,8 +62,7 @@
     <com.android.systemui.statusbar.LightRevealScrim
             android:id="@+id/light_reveal_scrim"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="gone" />
+            android:layout_height="match_parent" />
 
     <include layout="@layout/status_bar_expanded"
         android:layout_width="match_parent"
@@ -81,9 +80,10 @@
     />
 
     <!-- Keyguard messages -->
-    <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
         android:layout_marginTop="@dimen/status_bar_height"
         android:layout_gravity="top|center_horizontal"
         android:gravity="center_horizontal">
@@ -97,7 +97,11 @@
             android:singleLine="true"
             android:ellipsize="marquee"
             android:focusable="true" />
-    </FrameLayout>
+        <FrameLayout android:id="@+id/keyboard_bouncer_container"
+                     android:layout_height="0dp"
+                     android:layout_width="match_parent"
+                     android:layout_weight="1" />
+    </LinearLayout>
 
     <com.android.systemui.biometrics.AuthRippleView
         android:id="@+id/auth_ripple"
diff --git a/packages/SystemUI/res/layout/tile_service_request_dialog.xml b/packages/SystemUI/res/layout/tile_service_request_dialog.xml
new file mode 100644
index 0000000..b431d44
--- /dev/null
+++ b/packages/SystemUI/res/layout/tile_service_request_dialog.xml
@@ -0,0 +1,36 @@
+<?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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center_horizontal"
+>
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:textDirection="locale"
+        android:textAlignment="viewStart"
+        android:textAppearance="@style/TextAppearance.PrivacyDialog"
+        android:lineHeight="20sp"
+    />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
index 6218a5e..45b9f25 100644
--- a/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
@@ -26,7 +26,7 @@
 
     <ImageView
         android:id="@+id/chip_drawable"
-        android:layout_width="51dp"
+        android:layout_width="@dimen/privacy_chip_max_width"
         android:layout_height="@dimen/privacy_chip_height"
         android:minWidth="@dimen/privacy_chip_dot_bg_width"
         android:minHeight="@dimen/privacy_chip_dot_bg_height"
diff --git a/packages/SystemUI/res/layout/udfps_enroll_view.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml
index f1ff6d6..e41a632 100644
--- a/packages/SystemUI/res/layout/udfps_enroll_view.xml
+++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml
@@ -20,10 +20,23 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
+    <!-- The layout height/width are placeholders, which will be overwritten by
+         FingerprintSensorPropertiesInternal. -->
+    <View
+        android:id="@+id/udfps_enroll_accessibility_view"
+        android:layout_gravity="center"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:contentDescription="@string/accessibility_fingerprint_label"/>
+
+    <ImageView
+        android:id="@+id/udfps_enroll_animation_fp_progress_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
     <!-- Fingerprint -->
     <ImageView
         android:id="@+id/udfps_enroll_animation_fp_view"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:contentDescription="@string/accessibility_fingerprint_label"/>
+        android:layout_height="match_parent"/>
 </com.android.systemui.biometrics.UdfpsEnrollView>
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 18517906..a9eb27a 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -34,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"
@@ -46,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..51d9058 100644
--- a/packages/SystemUI/res/raw/udfps_aod_fp.json
+++ b/packages/SystemUI/res/raw/udfps_aod_fp.json
@@ -5,7 +5,7 @@
   "op":361,
   "w":46,
   "h":65,
-  "nm":"fingerprint_burn_in_Loop_02",
+  "nm":"fingerprint_burn_in_loop",
   "ddd":0,
   "assets":[
 
@@ -15,368 +15,6 @@
       "ddd":0,
       "ind":2,
       "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 9",
-      "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":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1,
-                "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":"tm",
-          "s":{
-            "a":0,
-            "k":0,
-            "ix":1
-          },
-          "e":{
-            "a":0,
-            "k":17,
-            "ix":2
-          },
-          "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  246
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  1326
-                ]
-              }
-            ],
-            "ix":3
-          },
-          "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
-          "mn":"ADBE Vector Filter - Trim",
-          "hd":false
-        },
-        {
-          "ty":"gr",
-          "it":[
-            {
-              "ty":"tm",
-              "s":{
-                "a":0,
-                "k":0,
-                "ix":1
-              },
-              "e":{
-                "a":0,
-                "k":17,
-                "ix":2
-              },
-              "o":{
-                "a":0,
-                "k":0,
-                "ix":3
-              },
-              "m":1,
-              "ix":1,
-              "nm":"Trim Paths 1",
-              "mn":"ADBE Vector Filter - Trim",
-              "hd":false
-            },
-            {
-              "ty":"tr",
-              "p":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "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":"Group 1",
-          "np":1,
-          "cix":2,
-          "bm":0,
-          "ix":3,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":3,
-      "ty":4,
       "nm":"Fingerprint_20210701 Outlines 8",
       "sr":1,
       "ks":{
@@ -526,13 +164,62 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":3,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -6
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -603,41 +290,12 @@
           },
           "e":{
             "a":0,
-            "k":54,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  1080
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
@@ -645,257 +303,6 @@
           "nm":"Trim Paths 1",
           "mn":"ADBE Vector Filter - Trim",
           "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":4,
-      "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 7",
-      "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
-                    ],
-                    [
-                      -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":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1,
-                "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":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
         },
         {
           "ty":"tm",
@@ -906,46 +313,17 @@
           },
           "e":{
             "a":0,
-            "k":38.2,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  170
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  890
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
+          "ix":3,
+          "nm":"Trim Paths 2",
           "mn":"ADBE Vector Filter - Trim",
           "hd":false
         }
@@ -957,7 +335,7 @@
     },
     {
       "ddd":0,
-      "ind":5,
+      "ind":3,
       "ty":4,
       "nm":"Fingerprint_20210701 Outlines 6",
       "sr":1,
@@ -1132,13 +510,62 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":3,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -6
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -1209,41 +636,12 @@
           },
           "e":{
             "a":0,
-            "k":34.2,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  720
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
@@ -1260,7 +658,7 @@
     },
     {
       "ddd":0,
-      "ind":6,
+      "ind":4,
       "ty":4,
       "nm":"Fingerprint_20210701 Outlines 5",
       "sr":1,
@@ -1507,13 +905,62 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":3,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -6
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -1584,416 +1031,12 @@
           },
           "e":{
             "a":0,
-            "k":35,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  -159
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  201
-                ]
-              }
-            ],
-            "ix":3
-          },
-          "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
-          "mn":"ADBE Vector Filter - Trim",
-          "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":7,
-      "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 4",
-      "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
-                    ],
-                    [
-                      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":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1,
-                "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":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        },
-        {
-          "ty":"tm",
-          "s":{
             "a":0,
             "k":0,
-            "ix":1
-          },
-          "e":{
-            "a":0,
-            "k":9,
-            "ix":2
-          },
-          "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  135
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  495
-                ]
-              }
-            ],
             "ix":3
           },
           "m":1,
@@ -2010,382 +1053,7 @@
     },
     {
       "ddd":0,
-      "ind":8,
-      "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 3",
-      "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
-                    ],
-                    [
-                      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":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1,
-                "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":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        },
-        {
-          "ty":"tm",
-          "s":{
-            "a":0,
-            "k":0,
-            "ix":1
-          },
-          "e":{
-            "a":0,
-            "k":30,
-            "ix":2
-          },
-          "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  360
-                ]
-              }
-            ],
-            "ix":3
-          },
-          "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
-          "mn":"ADBE Vector Filter - Trim",
-          "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":9,
+      "ind":5,
       "ty":4,
       "nm":"Fingerprint_20210701 Outlines",
       "sr":1,
@@ -2560,13 +1228,62 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":2.5,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -5
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -2637,41 +1354,12 @@
           },
           "e":{
             "a":0,
-            "k":69,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  720
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
@@ -2699,4 +1387,4 @@
       "dr":0
     }
   ]
-}
\ No newline at end of file
+}
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 daf4fdc7..028f14a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoem om skerm te vul"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Strek om skerm te vul"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock is gedeaktiveer"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Stoor tans skermkiekie..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om oop te maak"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Stawing word vereis. Raak die vingerafdruksensor om te staaf."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Oproep aan die gang"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Vliegtuigmodus"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Gekoppel"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet sal nie outomaties koppel nie"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data sal nie outomaties koppel nie"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding nie"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen ander netwerke beskikbaar nie"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Geen netwerke beskikbaar nie"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontsluit om netwerke te bekyk"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil die volgende teël by Kitsinstellings voeg"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Voeg teël by"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Moenie teël byvoeg nie"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0125b66..798e0c3 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ማያ እንዲሞላ አጉላ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ማያ ለመሙለት ሳብ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ተሰናክሏል"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ለመክፈት የጣት አሻራ ይጠቀሙ"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ማረጋገጥ ያስፈልጋል። ለማረጋገጥ የጣት አሻራ ዳሳሹን ይንኩ።"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"በመካሄድ ላይ የስልክ ጥሪ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"የአውሮፕላን ሁነታ"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"ተገናኝቷል"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"በይነመረብ በራስ-ሰር አይገናኝም"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ግንኙነት የለም"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ሌላ አውታረ መረብ የሉም"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ምንም አውታረ መረቦች የሉም"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"አውታረ መረቦችን ለመመልከት ይክፈቱ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> የሚከተለውን ሰቅ ወደ ፈጣን ቅንብሮች ማከል ይፈልጋል"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ሰቅ አክል"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ሰቅ አታክል"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 06bc4d5..6f5d73c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"تكبير/تصغير لملء الشاشة"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"توسيع بملء الشاشة"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"لقطة شاشة"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏تم إيقاف Smart Lock."</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"جارٍ حفظ لقطة الشاشة..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string>
@@ -184,6 +185,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>
@@ -1183,18 +1186,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"يمكنك استخدام بصمة الإصبع للفتح"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"المصادقة مطلوبة. المس مستشعر بصمات الإصبع للمصادقة."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"مكالمة هاتفية جارية"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"وضع الطيران"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"بيانات الجوّال"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"متصلة بالإنترنت"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"لن يتم الاتصال بالإنترنت تلقائيًا."</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"لن يتم تلقائيًا الاتصال ببيانات الجوّال."</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"لا يتوفّر اتصال بالإنترنت"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"لا تتوفّر شبكات أخرى."</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"لا تتوفّر أي شبكات."</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"فتح القفل لعرض الشبكات"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"يريد تطبيق <xliff:g id="APPNAME">%1$s</xliff:g> إضافة المربّع التالي إلى \"الإعدادات السريعة\""</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"إضافة مربّع"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"عدم إضافة مربّع"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 2dd3195..614e4d8 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্ৰীণ পূর্ণ কৰিবলৈ জুম কৰক"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"স্ক্ৰীণ পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock অক্ষম কৰা হৈছে"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
@@ -132,7 +133,7 @@
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"দিব্যাংগসকলৰ বাবে থকা সুবিধাসমূহ"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"স্ক্ৰীণ ঘূৰাওক"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"অৱলোকন"</string>
-    <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+    <string name="accessibility_search_light" msgid="524741790416076988">"সন্ধান কৰক"</string>
     <string name="accessibility_camera_button" msgid="2938898391716647247">"কেমেৰা"</string>
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ফ\'ন"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"কণ্ঠধ্বনিৰে সহায়"</string>
@@ -184,6 +185,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>
@@ -439,7 +442,7 @@
     <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"বেটাৰিৰ চ্চাৰ্জ সম্পূর্ণ হ\'বলৈ <xliff:g id="CHARGING_TIME">%s</xliff:g> বাকী"</string>
     <string name="expanded_header_battery_not_charging" msgid="809409140358955848">"চ্চার্জ কৰি থকা নাই"</string>
     <string name="ssl_ca_cert_warning" msgid="8373011375250324005">"নেটৱৰ্ক \nনিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
-    <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+    <string name="description_target_search" msgid="3875069993128855865">"সন্ধান কৰক"</string>
     <string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>ৰ বাবে ওপৰলৈ শ্লাইড কৰক।"</string>
     <string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>ৰ বাবে বাওঁফাললৈ শ্লাইড কৰক।"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্ম, ৰিমাইণ্ডাৰ, ইভেন্ট আৰু কল কৰোঁতাৰ বাহিৰে আন কোনো শব্দৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
@@ -1011,7 +1014,7 @@
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(কৰ্মস্থান)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ফ’ন কল"</string>
     <string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>ৰ জৰিয়তে)"</string>
-    <string name="privacy_type_camera" msgid="7974051382167078332">"কেমেৰা"</string>
+    <string name="privacy_type_camera" msgid="7974051382167078332">"Camera"</string>
     <string name="privacy_type_location" msgid="7991481648444066703">"অৱস্থান"</string>
     <string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্ৰ\'ফ\'ন"</string>
     <string name="sensor_privacy_mode" msgid="4462866919026513692">"ছেন্সৰ অফ হৈ আছে"</string>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলিবলৈ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণৰ আৱশ্যক। বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰিবলৈ ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক।"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"চলি থকা ফ’ন কল"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"এয়াৰপ্লেন ম\'ড"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ম’বাইল ডেটা"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"সংযোজিত হৈ আছে"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ইণ্টাৰনেট স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"সংযোগ নাই"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটৱর্ক চাবলৈ আনলক কৰক"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>এ ক্ষিপ্ৰ ছেটিঙত এই টাইলটো যোগ দিব বিচাৰিছে"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ দিয়ক"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ নিদিব"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b87b033..7cd3b32 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock deaktivdir"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmaq üçün barmaq izindən istifadə edin"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Doğrulanma tələb olunur. Doğrulamaq üçün barmaq izi sensoruna toxunun."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Davam edən zəng"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Uçuş rejimi"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Qoşulub"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"İnternet avtomatik qoşulmayacaq"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil data avtomatik qoşulmayacaq"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yoxdur"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Heç bir başqa şəbəkə əlçatan deyil"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Əlçatan şəbəkə yoxdur"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Şəbəkələrə baxmaq üçün kilidi açın"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aşağıdakı mozaiki Sürətli Ayarlara əlavə etmək istəyir"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Mozaik əlavə edin"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mozaik əlavə etməyin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 93e7c0c..f155b76 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj na celom ekranu"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci na ceo ekran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock je onemogućen"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Čuvanje snimka ekrana..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string>
@@ -184,6 +185,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>
@@ -1011,7 +1014,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
     <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
-    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Koristi <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Koristi: <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Nedavno koristio/la <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(posao)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonski poziv"</string>
@@ -1165,18 +1168,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je potvrda identiteta. Dodirnite senzor za otisak prsta da biste potvrdili identitet."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktuelni telefonski poziv"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Režim rada u avionu"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Automatsko povezivanje na internet nije moguće"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nije uspelo autom. povezivanje preko mob. podataka"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Veza nije uspostavljena"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da biste videli mreže"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi da doda sledeću pločicu u Brza podešavanja"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj pločicu"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne dodaj pločicu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ea4012c..ab3940b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Павял. на ўвесь экран"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Расцягн. на ўвесь экран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функцыя \"Smart Lock\" адключана"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Захаванне скрыншота..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Каб адкрыць, скарыстайце адбітак пальца"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Патрабуецца аўтэнтыфікацыя. Дакраніцеся да сканера адбіткаў пальцаў."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Бягучы тэлефонны выклік"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Рэжым палёту"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мабільная перадача даных"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Падключана"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Аўтаматычнае падключэнне да інтэрнэту адсутнічае"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мабільная перадача даных не ўключаецца аўтаматычна"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма падключэння"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Больш няма даступных сетак"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Няма даступных сетак"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблакіраваць для прагляду сетак"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> запытвае дазвол на дадаванне ў Хуткія налады наступнай пліткі"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Дадаць плітку"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не дадаваць плітку"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 389e71a..2d698ee 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Мащаб – запълва екрана"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Разпъване – запълва екрана"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Екранна снимка"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функцията Smart Lock е деактивирана"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Екранната снимка се запазва..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Използвайте отпечатък за отваряне"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Изисква се удостоверяване на самоличността. За целта докоснете сензора за отпечатъци."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Текущо телефонно обаждане"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Самолетен режим"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни данни"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Свързано"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Няма автоматично да се установи връзка с интернет"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Връзката за мобилни данни няма да е автоматична"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма връзка"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Няма други налични мрежи"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Няма налични мрежи"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отключване с цел преглед на мрежите"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> иска да добави следния панел към бързите настройки"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Добавяне на панел"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Отмяна на добавянето"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c856b8a..46172bd 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট নিন"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock বন্ধ করা হয়েছে"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"যাচাইকরণ করতে হবে। যাচাইকরণ করতে আঙুলের ছাপের সেন্সরে টাচ করুন।"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ব্যবহারকারী এখন ফোনে কথা বলছেন"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"বিমান মোড"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ইন্টারনেট অটোমেটিক কানেক্ট হবে না"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"কানেকশন নেই"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটওয়ার্ক দেখার জন্য আনলক করুন"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> নিম্নলিখিত টাইল দ্রুত সেটিংস মেনুতে যোগ করতে চায়"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ করুন"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ করবেন না"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 83a3e14..d6a6602 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Uvećaj prikaz na ekran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci prikaz na ekran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock je onemogućen"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spašavanje snimka ekrana..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string>
@@ -184,6 +185,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>
@@ -993,7 +996,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>
@@ -1165,18 +1168,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor za otisak prsta da autentificirate."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonski poziv u toku"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Način rada u avionu"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Prijenos podataka na mobilnoj mreži"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Nije se moguće automatski povezati s internetom"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Prijenos podataka se neće automatski povezati"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani s mrežom"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Druge mreže nisu dostupne"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da vidite mreže"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću karticu u Brze postavke"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj karticu"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nemoj dodati karticu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index b008d44..ea91dc1 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per omplir pantalla"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estira per omplir pant."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock desactivat"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"S\'està desant captura de pantalla..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string>
@@ -184,6 +185,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>
@@ -577,7 +580,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>
@@ -1006,7 +1009,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Algunes aplicacions estan fent servir el següent: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
     <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
-    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En ús per <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ho està utilitzant"</string>
     <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Utilitzat recentment per <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(feina)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Trucada"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilitza l\'empremta digital per obrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticació necessària. Toca el sensor d\'empremtes digitals per autenticar-te."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Trucada en curs"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Mode d\'avió"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dades mòbils"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connectat"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet no es connectarà automàticament"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Les dades mòbils no es connectaran automàticament"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sense connexió"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hi ha cap altra xarxa disponible"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No hi ha cap xarxa disponible"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueja per veure xarxes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vol afegir la icona següent a la configuració ràpida"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Afegeix la icona"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No afegeixis la icona"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ea9c4bb..c9021f8 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Přiblížit na celou obrazovku"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Na celou obrazovku"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funkce Smart Lock je deaktivována"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ukládání snímku obrazovky..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"K otevření použijte otisk prstu"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Je vyžadováno ověření. Dotkněte se snímače otisků prstů."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Probíhající hovor"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Režim Letadlo"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilní data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Připojeno"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet se nebude automaticky připojovat"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilní data se nebudou připojovat automaticky"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Žádné připojení"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Žádné další sítě nejsou k dispozici"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nejsou k dispozici žádné sítě"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sítě uvidíte po odemknutí"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikace <xliff:g id="APPNAME">%1$s</xliff:g> chce do Rychlého nastavení přidat následující dlaždici"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Přidat dlaždici"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepřidávat dlaždici"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bf5f367..c7214ff 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom til fuld skærm"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stræk til fuld skærm"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock er deaktiveret"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gemmer screenshot..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string>
@@ -184,6 +185,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>
@@ -381,7 +384,7 @@
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Manglende Wi-Fi-forbindelse"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"AUTO"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Byt om på farver"</string>
+    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Ombyt farver"</string>
     <string name="quick_settings_color_space_label" msgid="537528291083575559">"Farvekorrigeringstilstand"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere indstillinger"</string>
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brugerindstillinger"</string>
@@ -675,8 +678,8 @@
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
-    <string name="add_tile" msgid="6239678623873086686">"Tilføj et felt"</string>
-    <string name="broadcast_tile" msgid="5224010633596487481">"Broadcast-ikon"</string>
+    <string name="add_tile" msgid="6239678623873086686">"Tilføj felt"</string>
+    <string name="broadcast_tile" msgid="5224010633596487481">"Broadcast-felt"</string>
     <string name="zen_alarm_warning_indef" msgid="5252866591716504287">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>, medmindre du slår funktionen fra inden da"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -908,15 +911,15 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for notifikationer med lav prioritet"</string>
     <string name="other" msgid="429768510980739978">"Andet"</string>
-    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern kortet"</string>
-    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"føj kortet til slutningen"</string>
-    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt kortet"</string>
-    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj et kort"</string>
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern felt"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"føj feltet til slutningen"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt felt"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj felt"</string>
     <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flyt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
-    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kortet blev tilføjet"</string>
-    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kortet blev fjernet"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Feltet blev tilføjet"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Feltet blev fjernet"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsværktøj til Kvikmenu."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Åbn Indstillinger."</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Brug fingeraftryk for at åbne"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Godkendelse er påkrævet. Sæt fingeren på fingeraftrykslæseren for at godkende."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Igangværende telefonopkald"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Flytilstand"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Forbundet"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Der oprettes ikke automatisk internetforbindelse"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Der oprettes ikke automatisk mobildataforbindelse"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Der er ingen forbindelse"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Der er ingen andre tilgængelige netværk"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Der er ingen tilgængelige netværk"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås op for at se netværk"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil gerne føje dette handlingsfelt til Kvikmenu"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tilføj handlingsfelt"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tilføj ikke felt"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4d66246..6b5281e 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom auf Bildschirmgröße"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Auf Bildschirmgröße anpassen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock deaktiviert"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"Bild gesendet"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot wird gespeichert..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot wird gespeichert..."</string>
@@ -184,6 +185,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>
@@ -1083,7 +1086,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentifizierung erforderlich. Tippe dazu einfach auf den Fingerabdrucksensor."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktiver Anruf"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Flugmodus"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Keine automatische Verbindung mit dem Internet"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Keine Verbindung"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Keine anderen Netzwerke verfügbar"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Keine Netzwerke verfügbar"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Entsperren, um Netzwerke anzuzeigen"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> möchte die folgende Kachel den Schnelleinstellungen hinzufügen"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Kachel hinzufügen"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Kachel nicht hinzu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 091105e0..b55256c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ζουμ σε πλήρη οθόνη"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Προβoλή σε πλήρη οθ."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Το Smart Lock έχει απενεργοποιηθεί"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Αποθήκ. στιγμιότυπου οθόνης..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Χρήση δακτυλικού αποτυπώματος για άνοιγμα"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Απαιτείται έλεγχος ταυτότητας. Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων για έλεγχο ταυτότητας."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Τηλεφωνική κλήση σε εξέλιξη"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Λειτουργία πτήσης"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Δεδομένα κινητής τηλεφωνίας"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Συνδέθηκε"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Χωρίς αυτόματη σύνδεση στο διαδίκτυο"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Χωρίς αυτόματη σύνδεση δεδομένων κινητ. τηλεφωνίας"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Χωρίς σύνδεση"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Δεν υπάρχουν άλλα διαθέσιμα δίκτυα"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Δεν υπάρχουν διαθέσιμα δίκτυα"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ξεκλειδώστε για προβολή δικτύων"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Η εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g> θέλει να προσθέσει το παρακάτω πλακίδιο στις Γρήγορες ρυθμίσεις"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Προσθήκη πλακιδίου"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Χωρίς προσθ. πλακιδ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 479ea06..081bfcb 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Aeroplane mode"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet won\'t auto‑connect"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index b148b09..4e32027 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Aeroplane mode"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet won\'t auto‑connect"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 479ea06..081bfcb 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Aeroplane mode"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet won\'t auto‑connect"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 479ea06..081bfcb 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Aeroplane mode"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet won\'t auto‑connect"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index a3fec1d..6641705 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎Zoom to fill screen‎‏‎‎‏‎"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎Stretch to fill screen‎‏‎‎‏‎"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎Screenshot‎‏‎‎‏‎"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎Smart Lock disabled‎‏‎‎‏‎"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎sent an image‎‏‎‎‏‎"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎Saving screenshot…‎‏‎‎‏‎"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎Saving screenshot…‎‏‎‎‏‎"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‎Use fingerprint to open‎‏‎‎‏‎"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎Authentication required. Touch the fingerprint sensor to authenticate.‎‏‎‎‏‎"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎Ongoing phone call‎‏‎‎‏‎"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎Airplane mode‎‏‎‎‏‎"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎Mobile data‎‏‎‎‏‎"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="STATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ / ‎‏‎‎‏‏‎<xliff:g id="NETWORKMODE">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‏‎Connected‎‏‎‎‏‎"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎Internet won\'t auto‑connect‎‏‎‎‏‎"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎Mobile data won\'t auto‑connect‎‏‎‎‏‎"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎No connection‎‏‎‎‏‎"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎No other networks available‎‏‎‎‏‎"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎No networks available‎‏‎‎‏‎"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ wants to add the following tile to Quick Settings‎‏‎‎‏‎"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎Add tile‎‏‎‎‏‎"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎Do not add tile‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 166e16d..154248c 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ocupar la pantalla"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estirar p/ ocupar la pantalla"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Se inhabilitó Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura de pantalla"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella dactilar para abrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Se requiere de una autenticación. Toca el sensor de huellas dactilares para autenticarte."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modo de avión"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Conexión establecida"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"No se conectará automáticamente a Internet"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"No se conectarán automáticamente los datos móviles"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No hay redes disponibles"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver las redes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere agregar el siguiente azulejo a la Configuración rápida"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar azulejo"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar azulejo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index 5634f79..4f738c5 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -58,8 +58,8 @@
   </string-array>
   <string-array name="tile_states_flashlight">
     <item msgid="3465257127433353857">"No disponible"</item>
-    <item msgid="5044688398303285224">"Desactivado"</item>
-    <item msgid="8527389108867454098">"Activado"</item>
+    <item msgid="5044688398303285224">"Desactivada"</item>
+    <item msgid="8527389108867454098">"Activada"</item>
   </string-array>
   <string-array name="tile_states_rotation">
     <item msgid="4578491772376121579">"No disponible"</item>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3b06d9b..8e19028 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ajustar"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Expandir para ajustar"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock inhabilitado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string>
@@ -184,6 +185,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>
@@ -675,8 +678,8 @@
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ajustes de pantalla de bloqueo"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
-    <string name="add_tile" msgid="6239678623873086686">"Añadir icono"</string>
-    <string name="broadcast_tile" msgid="5224010633596487481">"Icono de emisión"</string>
+    <string name="add_tile" msgid="6239678623873086686">"Añadir recuadro"</string>
+    <string name="broadcast_tile" msgid="5224010633596487481">"Recuadro de emisión"</string>
     <string name="zen_alarm_warning_indef" msgid="5252866591716504287">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>) a menos que desactives esta opción antes"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
     <string name="alarm_template" msgid="2234991538018805736">"a las <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -890,10 +893,10 @@
     <string name="right_keycode" msgid="2480715509844798438">"Código de teclado a la derecha"</string>
     <string name="left_icon" msgid="5036278531966897006">"Icono a la izquierda"</string>
     <string name="right_icon" msgid="1103955040645237425">"Icono a la derecha"</string>
-    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Pulsa y arrastra para añadir funciones"</string>
-    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén pulsado un icono y arrástralo para reubicarlo"</string>
+    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Pulsa y arrastra para añadir recuadros"</string>
+    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén pulsado un recuadro y arrástralo para reubicarlo"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastra aquí para quitar una función"</string>
-    <string name="drag_to_remove_disabled" msgid="933046987838658850">"Necesitas al menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> iconos"</string>
+    <string name="drag_to_remove_disabled" msgid="933046987838658850">"Necesitas al menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> recuadros"</string>
     <string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
     <string name="tuner_time" msgid="2450785840990529997">"Hora"</string>
   <string-array name="clock_options">
@@ -908,15 +911,15 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar iconos de notificaciones con prioridad baja"</string>
     <string name="other" msgid="429768510980739978">"Otros"</string>
-    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar icono"</string>
-    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"añadir icono al final"</string>
-    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover icono"</string>
-    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Añadir icono"</string>
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar recuadro"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"añadir recuadro al final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover recuadro"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Añadir recuadro"</string>
     <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Añadir a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
-    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tarjeta añadida"</string>
-    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tarjeta quitada"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Recuadro añadido"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Recuadro quitado"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de ajustes rápidos."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir ajustes."</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella digital para abrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticación obligatoria. Toca el sensor de huellas digitales para autenticarte."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modo avión"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet no se conecta automáticamente"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"No hay redes disponibles"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver redes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere añadir el siguiente recuadro a ajustes rápidos"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Añadir recuadro"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No añadir recuadro"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 625b466..d603182 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Suumi ekraani täitmiseks"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Venita ekraani täitmiseks"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock on keelatud"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Kuvatõmmise salvestamine ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Kasutage avamiseks sõrmejälge"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vajalik on autentimine. Puudutage autentimiseks sõrmejäljeandurit."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Käimasolev telefonikõne"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Lennukirežiim"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilne andmeside"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Ühendatud"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internetiühendust ei looda automaatselt"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilset andmesideühendust ei looda automaatselt"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ühendus puudub"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ühtegi muud võrku pole saadaval"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Ühtegi võrku pole saadaval"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Võrkude vaatamiseks avage"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> soovib kiirseadetesse lisada järgmise paani"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lisa paan"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ära lisa paani"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index fa50729..d59dc7a 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -58,7 +58,7 @@
     <string name="always_use_device" msgid="210535878779644679">"Ireki <xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g> konektatzen den guztietan"</string>
     <string name="always_use_accessory" msgid="1977225429341838444">"Ireki <xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> konektatzen den guztietan"</string>
     <string name="usb_debugging_title" msgid="8274884945238642726">"USB bidezko arazketa onartu?"</string>
-    <string name="usb_debugging_message" msgid="5794616114463921773">"Ordenagailuaren RSA gakoaren erreferentzia-gako digitala hau da:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="5794616114463921773">"Ordenagailuaren RSA gakoaren aztarna digitala hau da:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="4003121804294739548">"Eman beti ordenagailu honetatik arazteko baimena"</string>
     <string name="usb_debugging_allow" msgid="1722643858015321328">"Eman baimena"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ez da onartzen USB bidezko arazketa"</string>
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Handiagotu pantaila betetzeko"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Luzatu pantaila betetzeko"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Desgaitu da Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Pantaila-argazkia gordetzen…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string>
@@ -184,6 +185,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>
@@ -575,7 +578,7 @@
     <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Ireki kredentzial fidagarriak"</string>
     <string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratzaileak sarearen erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
-    <string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikazio bati VPN konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
+    <string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikazio bati VPN bidezko konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen du zure laneko profila.\n\nAdministratzaileak sareko jarduerak kontrola diezazkizuke, besteak beste, posta elektronikoa, aplikazioak eta webguneak.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nHorrez gain, VPN batera zaude konektatuta, eta hark ere kontrola ditzake zure sareko jarduerak."</string>
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Zure gurasoak kudeatzen du gailua. Zure gurasoak gailuko informazioa ikusi eta kudea dezake; besteak beste, zer aplikazio erabiltzen dituzun, zure kokapena zein den eta pantaila aurrean zenbat eta noiz egoten zaren."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN konexioa"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Erabili hatz-marka irekitzeko"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentifikazioa behar da. Autentifikatzeko, ukitu hatz-marken sentsorea."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefono-dei bat abian da"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Hegaldi modua"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datu-konexioa"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> (<xliff:g id="NETWORKMODE">%2$s</xliff:g>)"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Konektatuta"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Ez da automatikoki konektatuko Internetera"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Ez da automatikoki aktibatuko datu-konexioa"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Konexiorik gabe"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ez dago beste sare erabilgarririk"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Ez dago sare erabilgarririk"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sareak ikusteko, desblokeatu pantaila"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak lauza hau gehitu nahi du Ezarpen bizkorrak menuan:"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Gehitu lauza"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ez gehitu lauza"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 41e895b..62281ef 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"بزرگ‌نمایی برای پر کردن صفحه"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"گسترده کردن برای پر کردن صفحه"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"نماگرفت"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏Smart Lock غیرفعال شد"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"تصویری ارسال کرد"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"در حال ذخیره نماگرفت..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"درحال ذخیره نماگرفت…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"از اثر انگشت برای باز کردن قفل استفاده کنید"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"اصالت‌سنجی لازم است. برای اصالت‌سنجی، حسگر اثر انگشت را لمس کنید."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"تماس تلفنی درحال انجام"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"حالت هواپیما"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"داده تلفن همراه"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"متصل است"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"اینترنت به‌طور خودکار متصل نخواهد شد"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"داده تلفن همراه به‌طور خودکار متصل نخواهد شد"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"اتصال برقرار نیست"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"شبکه دیگری وجود ندارد"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"شبکه‌ای در دسترس نیست"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"برای مشاهده شبکه‌ها، قفل صفحه را باز کنید"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> می‌خواهد کاشی زیر را به «تنظیمات فوری» اضافه کند"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"افزودن کاشی"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"کاشی اضافه نشود"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 76b245f..629b1ff 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoomaa koko näyttöön"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Venytä koko näyttöön"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock poistettu käytöstä"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Tallennetaan kuvakaappausta..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string>
@@ -184,6 +185,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>
@@ -858,7 +861,7 @@
     <string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Kuulokemikrofoni liitetty"</string>
     <string name="data_saver" msgid="3484013368530820763">"Data Saver"</string>
     <string name="accessibility_data_saver_on" msgid="5394743820189757731">"Data Saver on käytössä."</string>
-    <string name="accessibility_data_saver_off" msgid="58339669022107171">"Data Saver on pois käytöstä."</string>
+    <string name="accessibility_data_saver_off" msgid="58339669022107171">"Data Saver on pois päältä."</string>
     <string name="switch_bar_on" msgid="1770868129120096114">"Päällä"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Pois päältä"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ei käytettävissä"</string>
@@ -973,9 +976,9 @@
     <string name="mobile_data" msgid="4564407557775397216">"Mobiilitiedonsiirto"</string>
     <string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
-    <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois käytöstä"</string>
+    <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois päältä"</string>
     <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ei ole käytössä"</string>
-    <string name="dnd_is_off" msgid="3185706903793094463">"Älä häiritse ‑tila on pois käytöstä"</string>
+    <string name="dnd_is_off" msgid="3185706903793094463">"Älä häiritse ‑tila on pois päältä"</string>
     <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Automaattinen sääntö otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Sovellus otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Automaattinen sääntö tai sovellus otti käyttöön Älä häiritse ‑tilan."</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Avaa sormenjäljellä"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Todennus vaaditaan. Todenna koskettamalla sormenjälkitunnistinta."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Puhelu käynnissä"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Lentokonetila"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilidata"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Yhdistetty"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internetyhteyttä ei muodosteta automaattisesti"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilidata ei yhdisty automaattisesti"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ei yhteyttä"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ei muita verkkoja käytettävissä"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Ei verkkoja käytettävissä"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Avaa lukitus nähdäksesi verkot"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> haluaa lisätä seuraavan laatan pika-asetuksiin"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lisää laatta"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Älä lisää laattaa"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 788a319..a13f849 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Fonctionnalité Smart Lock désactivée"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string>
@@ -184,6 +185,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>
@@ -1006,7 +1009,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
     <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
-    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En cours d\'utilisation par <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En cours d\'utilisation par : <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Récemment utilisé par <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(travail)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Appel téléphonique"</string>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Servez-vous de votre empreinte digitale pour ouvrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Touchez le capteur d\'empreintes digitales pour vous authentifier."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Appel téléphonique en cours…"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Mode Avion"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données cellulaires"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connexion active"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Connexion automatique à Internet impossible"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau n\'est accessible"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Aucun réseau n\'est accessible"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouillez l\'écran pour afficher les réseaux Wi-Fi"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"L\'application <xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter la tuile suivante au menu Paramètres rapides"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter tuile"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 645c970..f0bc8be 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock désactivé"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilisez votre empreinte pour ouvrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Appuyez sur le lecteur d\'empreintes digitales pour vous authentifier."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Appel téléphonique en cours"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Mode Avion"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Pas de connexion automatique à Internet"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Pas de connexion automatique des données mobiles"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau disponible"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Aucun réseau disponible"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouiller pour afficher les réseaux"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter le bloc suivant aux Réglages rapides"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter un bloc"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter bloc"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 88098a0..d6f8036 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock está desactivado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string>
@@ -184,6 +185,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>
@@ -1006,7 +1009,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hai aplicacións que están utilizando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
     <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
-    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Opción en uso por <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En uso por: <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Opción usada recentemente por <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(traballo)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Chamada de teléfono"</string>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa a impresión dixital para abrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Requírese autenticación. Para autenticarte, toca o sensor de impresión dixital."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada telefónica en curso"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modo avión"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móbiles"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectada"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet non se conectará automaticamente"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sen conexión"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Non hai outras redes dispoñibles"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Non hai redes dispoñibles"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea a pantalla para ver as redes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> solicita a túa aprobación para engadir o seguinte atallo a Configuración rápida"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Engadir atallo"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non engadir atallo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 2f09896..11fe9b9 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"સ્ક્રીન ભરવા માટે ઝૂમ કરો"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"સ્ક્રીન ભરવા માટે ખેંચો"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock બંધ કરેલું છે"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
@@ -133,7 +134,7 @@
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"સ્ક્રીન ફેરવો"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"ઝલક"</string>
     <string name="accessibility_search_light" msgid="524741790416076988">"શોધ"</string>
-    <string name="accessibility_camera_button" msgid="2938898391716647247">"કૅમેરો"</string>
+    <string name="accessibility_camera_button" msgid="2938898391716647247">"કૅમેરા"</string>
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ફોન"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"વૉઇસ સહાય"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"વૉલેટ"</string>
@@ -184,6 +185,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>
@@ -980,7 +983,7 @@
     <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ખલેલ પાડશો નહીં એક ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ખલેલ પાડશો નહીં એક સ્વચાલિત નિયમ અથવા ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું."</string>
     <string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> સુધી"</string>
-    <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
+    <string name="qs_dnd_keep" msgid="3829697305432866434">"રાખો"</string>
     <string name="qs_dnd_replace" msgid="7712119051407052689">"બદલો"</string>
     <string name="running_foreground_services_title" msgid="5137313173431186685">"પૃષ્ઠભૂમિમાં ચાલી રહેલ ઍપ્લિકેશનો"</string>
     <string name="running_foreground_services_msg" msgid="3009459259222695385">"બૅટરી અને ડેટા વપરાશ વિશેની વિગતો માટે ટૅપ કરો"</string>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"પ્રમાણીકરણ આવશ્યક છે. પ્રમાણિત કરવા માટે ફિંગરપ્રિન્ટ સેન્સરને ટચ કરો."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ફોન કૉલ ચાલુ છે"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"એરપ્લેન મોડ"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ઇન્ટરનેટ ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"કોઈ કનેક્શન નથી"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"બીજાં કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"વાઇ-ફાઇ નેટવર્ક જોવા માટે અનલૉક કરો"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ઝડપી સેટિંગમાં <xliff:g id="APPNAME">%1$s</xliff:g> નીચે જણાવેલા ટાઇલ ઉમેરવા માગે છે"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ટાઇલ ઉમેરો"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ટાઇલ ઉમેરશો નહીં"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 9b6ce4f..44100dc 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"स्‍क्रीन भरने के लिए ज़ूम करें"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"स्‍क्रीन भरने के लिए खींचें"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock की सुविधा बंद कर दी गई है"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
@@ -184,6 +185,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>
@@ -845,7 +848,7 @@
     <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"मैसेज (एसएमएस) करें"</string>
     <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
     <string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string>
-    <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कैलेंडर"</string>
+    <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
     <string name="tuner_full_zen_title" msgid="5120366354224404511">"वॉल्यूम नियंत्रणों के साथ दिखाएं"</string>
     <string name="volume_and_do_not_disturb" msgid="502044092739382832">"परेशान न करें"</string>
     <string name="volume_dnd_silent" msgid="4154597281458298093">"वॉल्यूम बटन का शॉर्टकट"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि करना ज़रूरी है. पुष्टि करने के लिए, फ़िंगरप्रिंट सेंसर को छुएं."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"फ़ोन कॉल चल रहा है"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"हवाई जहाज़ मोड"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट हो गया"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"इंटरनेट अपने-आप कनेक्ट नहीं होगा"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा अपने-आप कनेक्ट नहीं होगा"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"इंटरनेट कनेक्शन नहीं है"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"कोई दूसरा नेटवर्क उपलब्ध नहीं है"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"कोई नेटवर्क उपलब्ध नहीं है"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"वाई-फ़ाई नेटवर्क देखने के लिए, स्क्रीन को अनलॉक करें"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> इस टाइल को \'फटाफट सेटिंग\' में जोड़ने के लिए अनुमति चाहता है"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोड़ें"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल न जोड़ें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2892e66..ed1f3cb 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj i ispuni zaslon"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rastegni i ispuni zaslon"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snimka zaslona"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock onemogućen"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spremanje snimke zaslona..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string>
@@ -184,6 +185,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>
@@ -1165,18 +1168,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor otiska prsta da biste se autentificirali."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonski poziv u tijeku"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Način rada u zrakoplovu"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Neće biti automatskog povezivanja s internetom"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilni podaci neće se automatski povezati"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte za prikaz mreža"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću pločicu u Brze postavke"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj pločicu"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nemoj dodati pločicu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 079c915..b47e75b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Nagyítás a kitöltéshez"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Nyújtás kitöltéshez"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock kikapcsolva"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Képernyőkép mentése..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string>
@@ -184,6 +185,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>
@@ -351,7 +354,7 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Beviteli módszer"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Hely kikapcsolva"</string>
-    <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraelérés"</string>
+    <string name="quick_settings_camera_label" msgid="5612076679385269339">"Hozzáférés a kamerához"</string>
     <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonelérés"</string>
     <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Rendelkezésre áll"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Letiltva"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ujjlenyomat használata a megnyitáshoz"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Hitelesítés szükséges. Érintse meg az ujjlenyomat-érzékelőt a hitelesítéshez."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Folyamatban lévő telefonhívás"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Repülős üzemmód"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiladat"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g>/<xliff:g id="STATE">%1$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Csatlakozva"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Az internetre történő csatlakozás nem automatikus"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nincs automatikus mobiladat-kapcsolat"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nincs kapcsolat"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nincs több rendelkezésre álló hálózat"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nincs rendelkezésre álló hálózat"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> a következő mozaikot szeretné hozzáadni a Gyorsbeállításokhoz"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Mozaik hozzáadása"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne legyen hozzáadva"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7df2efb..0fcfd65 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Խոշորացնել` էկրանը լցնելու համար"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ձգել` էկրանը լցնելու համար"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock-ն անջատված է"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Սքրինշոթը պահվում է…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Բացելու համար օգտագործեք մատնահետքը"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Պահանջվում է նույնականացում։ Դրա համար մատը հպեք մատնահետքի սկաներին։"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ընթացիկ հեռախոսազանգ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Ավիառեժիմ"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Բջջային ինտերնետ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Միացած է"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Չհաջողվեց ավտոմատ միանալ համացանցին"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Բջջային ինտերնետն ավտոմատ չի միանա"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Կապ չկա"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Այլ հասանելի ցանցեր չկան"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Հասանելի ցանցեր չկան"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ապակողպեք՝ ցանցերը դիտելու համար"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածն ուզում է ավելացնել հետևյալ սալիկը Արագ կարգավորումներում"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ավելացնել սալիկ"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Չավելացնել սալիկ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 07a5672..6486b0b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Perbesar utk mengisi layar"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rentangkn utk mngisi layar"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dinonaktifkan"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan screenshot..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string>
@@ -184,11 +185,13 @@
     <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>
     <string name="accessibility_compatibility_zoom_example" msgid="2617218726091234073">"Perbesar dari layar kecil ke besar."</string>
-    <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tersambung."</string>
+    <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string>
     <string name="accessibility_bluetooth_disconnected" msgid="7195823280221275929">"Bluetooth terputus."</string>
     <string name="accessibility_no_battery" msgid="3789287732041910804">"Tidak ada baterai."</string>
     <string name="accessibility_battery_one_bar" msgid="8868347318237585329">"Baterai satu batang."</string>
@@ -213,8 +216,8 @@
     <string name="accessibility_signal_full" msgid="5920148525598637311">"Sinyal penuh."</string>
     <string name="accessibility_desc_on" msgid="2899626845061427845">"Aktif."</string>
     <string name="accessibility_desc_off" msgid="8055389500285421408">"Nonaktif."</string>
-    <string name="accessibility_desc_connected" msgid="3082590384032624233">"Tersambung."</string>
-    <string name="accessibility_desc_connecting" msgid="8011433412112903614">"Menyambung."</string>
+    <string name="accessibility_desc_connected" msgid="3082590384032624233">"Terhubung."</string>
+    <string name="accessibility_desc_connecting" msgid="8011433412112903614">"Menghubungkan."</string>
     <string name="data_connection_hspa" msgid="6096234094857660873">"HSPA"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
     <string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string>
@@ -269,7 +272,7 @@
     <string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth nonaktif."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aktif."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="7362294657419149294">"Bluetooth menyambung."</string>
-    <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"Bluetooth tersambung."</string>
+    <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"Bluetooth terhubung."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"Bluetooth dinonaktifkan."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"Bluetooth diaktifkan."</string>
     <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"Pelaporan lokasi nonaktif."</string>
@@ -387,9 +390,9 @@
     <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setelan pengguna"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
     <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string>
-    <string name="quick_settings_connected" msgid="3873605509184830379">"Tersambung"</string>
+    <string name="quick_settings_connected" msgid="3873605509184830379">"Terhubung"</string>
     <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Terhubung, baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
-    <string name="quick_settings_connecting" msgid="2381969772953268809">"Menyambung..."</string>
+    <string name="quick_settings_connecting" msgid="2381969772953268809">"Menghubungkan..."</string>
     <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Menambatkan"</string>
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Mengaktifkan…"</string>
@@ -560,30 +563,30 @@
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Otoritas sertifikat diinstal di perangkat. Traffic jaringan aman Anda mungkin dipantau atau diubah."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat."</string>
     <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di profil kerja, tetapi tidak di profil pribadi."</string>
-    <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
-    <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Anda tersambung ke <xliff:g id="VPN_APP_0">%1$s</xliff:g> dan <xliff:g id="VPN_APP_1">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
-    <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Profil kerja Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
-    <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Profil pribadi Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
+    <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
+    <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Anda terhubung ke <xliff:g id="VPN_APP_0">%1$s</xliff:g> dan <xliff:g id="VPN_APP_1">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
+    <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Profil kerja Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
+    <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Profil pribadi Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
     <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"Perangkat dikelola oleh <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> menggunakan <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> untuk mengelola perangkat Anda."</string>
     <string name="monitoring_description_do_body" msgid="7700878065625769970">"Admin dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat."</string>
     <string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="645149183455573790">"Pelajari lebih lanjut"</string>
-    <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
+    <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Buka setelan VPN"</string>
     <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Buka kredensial terpercaya"</string>
     <string name="monitoring_description_network_logging" msgid="577305979174002252">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat.\n\nUntuk informasi selengkapnya, hubungi admin."</string>
     <string name="monitoring_description_vpn" msgid="1685428000684586870">"Anda memberikan izin kepada aplikasi untuk menyiapkan sambungan VPN.\n\nAplikasi ini ini dapat memantau aktivitas perangkat dan jaringan, termasuk email, aplikasi, dan situs web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdmin dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin.\n\nAnda juga tersambung ke VPN, yang dapat memantau aktivitas jaringan."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdmin dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin.\n\nAnda juga terhubung ke VPN, yang dapat memantau aktivitas jaringan."</string>
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Perangkat ini dikelola oleh orang tuamu. Orang tuamu bisa melihat dan mengelola berbagai informasi, seperti aplikasi yang kamu gunakan, lokasimu, dan lama pemakaian perangkat."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
-    <string name="monitoring_description_app" msgid="376868879287922929">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
-    <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
-    <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
-    <string name="monitoring_description_app_work" msgid="3713084153786663662">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs.\n\nHubungi admin untuk mendapatkan informasi lebih lanjut."</string>
-    <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
+    <string name="monitoring_description_app" msgid="376868879287922929">"Anda terhubung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
+    <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Anda terhubung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Anda terhubung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
+    <string name="monitoring_description_app_work" msgid="3713084153786663662">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil terhubung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs.\n\nHubungi admin untuk mendapatkan informasi lebih lanjut."</string>
+    <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil terhubung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs.\n\nAnda juga terhubung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Tetap terbuka kuncinya oleh TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Perangkat akan tetap terkunci hingga Anda membukanya secara manual"</string>
     <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan sidik jari untuk membuka"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Perlu autentikasi. Sentuh sensor sidik jari untuk melakukan autentikasi."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Panggilan telepon sedang berlangsung"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Mode pesawat"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data seluler"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Terhubung"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet tidak akan terhubung otomatis"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data seluler tidak akan terhubung otomatis"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Tidak ada koneksi"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Jaringan lain tidak tersedia"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Jaringan tidak tersedia"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat jaringan"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ingin menambahkan kartu berikut ke Setelan Cepat"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan kartu"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah kartu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index d58cdc8..110eb09 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktif"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mengakses mikrofon"</string>
-    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN tersambung"</string>
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN terhubung"</string>
     <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN terputus"</string>
     <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
     <string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifikasi"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index fbcbddb..0af672c 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Fylla skjá með aðdrætti"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Teygja yfir allan skjáinn"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Slökkt á Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Vistar skjámynd…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Opna með fingrafari"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Auðkenningar krafist. Auðkenndu með því að snerta fingrafaralesarann."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Símtal í gangi"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Flugstilling"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Farsímagögn"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Tengt"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internetið tengist ekki sjálfkrafa"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Farsímagögn tengjast ekki sjálfkrafa"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Engin tenging"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Engin önnur net í boði"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Ekkert net í boði"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Taktu úr lás til að skoða netkerfi"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vill bæta eftirfarandi reit við flýtistillingar"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Bæta reit við"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ekki bæta reit við"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 52b5879..d2f6335 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per riempire schermo"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funzionalità Smart Lock disattivata"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa l\'impronta per aprire"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticazione obbligatoria. Eseguila toccando il sensore di impronte digitali."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonata in corso"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modalità aereo"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dati mobili"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connessione attiva"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet non si connetterà automaticamente"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nessuna connessione dati mobili automatica"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nessuna connessione"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nessun\'altra rete disponibile"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nessuna rete disponibile"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sblocca per visualizzare le reti"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vuole aggiungere il seguente riquadro alle Impostazioni rapide"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Aggiungi riquadro"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 7dce350..78370d6 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"הגדלת התצוגה למילוי המסך"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"מתיחה למילוי של המסך"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏השבתת את Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"צילום המסך נשמר..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"המערכת שומרת את צילום המסך..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"נדרש אימות. יש לגעת בחיישן טביעות האצבע כדי לבצע אימות."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"מתקיימת שיחה"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"מצב טיסה"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"חבילת גלישה"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"מחובר"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"לא ניתן להתחבר לאינטרנט באופן אוטומטי"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"החיבור לנתונים סלולריים לא מתבצע באופן אוטומטי"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"אין חיבור"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"אין רשתות זמינות אחרות"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"אין רשתות זמינות"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> מבקשת להוסיף להגדרות המהירות את האריח הבא"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"הוספת אריח"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"אין להוסיף אריח"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9c9bd42..7e8c6a1 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"画面サイズに合わせて拡大"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"画面サイズに合わせて拡大"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock は無効です"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"スクリーンショットを保存中..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"指紋を使って開いてください"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"認証が必要です。指紋認証センサーをタッチして認証してください。"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"機内モード"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"モバイルデータ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"接続済み"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"インターネットに自動的に接続されません"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"モバイルデータには自動接続しません"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"接続なし"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"利用できるネットワークはありません"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ネットワークを利用できません"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ネットワークを表示するにはロック解除してください"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> が以下のタイルをクイック設定に追加しようとしています"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"タイルを追加"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"タイルを追加しない"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4b9ab21..f7bcf7f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"გაწიეთ ეკრანის შესავსებად."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock გათიშულია"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"სკრინშოტის შენახვა…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"გასახსნელად გამოიყენეთ თითის ანაბეჭდი"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"საჭიროა ავტორიზაცია. ავტორიზაციისთვის შეეხეთ თითის ანაბეჭდის სენსორს."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"მიმდინარე სატელეფონო ზარი"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"თვითმფრინავის რეჟიმი"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"მობილური ინტერნეტი"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"დაკავშირებული"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ინტერნეტს ავტომატურად არ დაუკავშირდება"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"მობილურ ინტერნეტს ავტომატურად არ დაუკავშირდება"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"კავშირი არ არის"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"სხვა ქსელები მიუწვდომელია"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ქსელები მიუწვდომელია"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"განბლოკვა ქსელების სანახავად"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>-ს სურს, დაამატოს შემდეგი მოზაიკა სწრაფ პარამეტრებში"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"მოზაიკის დამატება"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"არ დაემატოს მოზაიკა"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index e9d6067..92b93a0 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Экранды толтыру үшін ұлғайту"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтыру үшін созу"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock өшірілді"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншотты сақтауда…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ашу үшін саусақ ізін пайдаланыңыз."</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аутентификациядан өту қажет. Ол үшін саусақ ізін оқу сканерін түртіңіз."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Телефон қоңырауы бар"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Ұшақ режимі"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильдік интернет"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Жалғанды"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Интернет автоматты түрде қосылмайды."</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобильдік интернет автоматты түрде қосылмайды."</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыс жоқ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Басқа қолжетімді желі жоқ"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Қолжетімді желілер жоқ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Желілерді көру үшін құлыпты ашыңыз."</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> Жылдам параметрлерге келесі бөлшекті қосқысы келеді."</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Бөлшек қосу"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Бөлшек қоспау"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 52d91f3..2b25be6 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ពង្រីក​​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ទាញ​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"បានបិទ Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បាន​ផ្ញើរូបភាព"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ប្រើស្នាមម្រាមដៃ ដើម្បីបើក"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"តម្រូវឱ្យ​មាន​ការផ្ទៀងផ្ទាត់។ សូមចុច​ឧបករណ៍​ចាប់ស្នាមម្រាមដៃ ដើម្បី​ផ្ទៀងផ្ទាត់​។"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ការហៅទូរសព្ទ​ដែលកំពុង​ដំណើរការ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ពេលជិះ​យន្តហោះ"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ទិន្នន័យ​ទូរសព្ទចល័ត"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"បានភ្ជាប់"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"អ៊ីនធឺណិតនឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"ទិន្នន័យទូរសព្ទចល័ត​នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"មិនមាន​ការតភ្ជាប់ទេ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"មិន​មាន​បណ្ដាញផ្សេងទៀតដែល​អាច​ប្រើ​បានទេ"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"មិន​មាន​បណ្ដាញដែល​អាច​ប្រើ​បានទេ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ដោះសោ​ដើម្បីមើល​បណ្ដាញ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ចង់បញ្ចូល​ប្រអប់​ខាងក្រោម​ទៅក្នុង​ការកំណត់រហ័ស"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"បញ្ចូល​ប្រអប់"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"កុំ​បញ្ចូល​ប្រអប់"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index f23153d..13b4bd7 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
@@ -132,7 +133,7 @@
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"ಪ್ರವೇಶಿಸುವಿಕೆ"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"ಪರದೆಯನ್ನು ತಿರುಗಿಸಿ"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"ಸಮಗ್ರ ನೋಟ"</string>
-    <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+    <string name="accessibility_search_light" msgid="524741790416076988">"ಹುಡುಕಿ"</string>
     <string name="accessibility_camera_button" msgid="2938898391716647247">"ಕ್ಯಾಮರಾ"</string>
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ಫೋನ್"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
@@ -184,6 +185,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>
@@ -439,7 +442,7 @@
     <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ"</string>
     <string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ಚಾರ್ಜ್‌ ಆಗುತ್ತಿಲ್ಲ"</string>
     <string name="ssl_ca_cert_warning" msgid="8373011375250324005">"ನೆಟ್‌ವರ್ಕ್\n ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
-    <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+    <string name="description_target_search" msgid="3875069993128855865">"ಹುಡುಕಿ"</string>
     <string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
     <string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಎಡಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"ಅಲಾರಾಂಗಳು, ಜ್ಞಾಪನೆಗಳು, ಈವೆಂಟ್‌ಗಳು ಹಾಗೂ ನೀವು ಸೂಚಿಸಿರುವ ಕರೆದಾರರನ್ನು ಹೊರತುಪಡಿಸಿ ಬೇರಾವುದೇ ಸದ್ದುಗಳು ಅಥವಾ ವೈಬ್ರೇಶನ್‌ಗಳು ನಿಮಗೆ ತೊಂದರೆ ನೀಡುವುದಿಲ್ಲ. ಹಾಗಿದ್ದರೂ, ನೀವು ಪ್ಲೇ ಮಾಡುವ ಸಂಗೀತ, ವೀಡಿಯೊಗಳು ಮತ್ತು ಆಟಗಳ ಆಡಿಯೊವನ್ನು ನೀವು ಕೇಳಿಸಿಕೊಳ್ಳುತ್ತೀರಿ."</string>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ದೃಢೀಕರಣದ ಅವಶ್ಯಕತೆಯಿದೆ. ದೃಢೀಕರಿಸಲು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಫೋನ್ ಕರೆ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ಇಂಟರ್ನೆಟ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ಯಾವುದೇ ಕನೆಕ್ಷನ್ ಇಲ್ಲ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ಇತರ ಯಾವುದೇ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ಯಾವುದೇ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ಈ ಕೆಳಗಿನ ಟೈಲ್ ಅನ್ನು ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳಿಗೆ ಸೇರಿಸಲು ಬಯಸುತ್ತದೆ"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಬೇಡಿ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3344ddc..81b0ec0 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"전체화면 모드로 확대"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"전체화면 모드로 확대"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 사용 중지됨"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"캡쳐화면 저장 중..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"지문으로 열기"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"인증이 필요합니다. 지문 센서를 터치하여 인증하세요."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"진행 중인 전화 통화"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"비행기 모드"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"모바일 데이터"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"연결됨"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"인터넷에 자동으로 연결되지 않음"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"모바일 데이터가 자동으로 연결되지 않음"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"연결되지 않음"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"사용 가능한 다른 네트워크가 없음"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"사용 가능한 네트워크가 없음"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"네트워크를 보려면 잠금 해제하세요"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>에서 빠른 설정에 다음 타일을 추가하려고 합니다."</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"타일 추가"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"타일 추가 안함"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index df621e5..3161270 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Экрнд тлтр ү. чен өлч өзг"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтуруу ү-н чоюу"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock өчүрүлдү"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншот сакталууда…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Манжаңыздын изи менен ачыңыз"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аныктыкты текшерүү талап кылынат. Аныктыгын текшерүү үчүн манжа изинин сенсоруна тийип коюңуз."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Учурдагы телефон чалуу"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Учак режими"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилдик трафик"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Туташты"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Интернет автоматтык түрдө туташпайт"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилдик трафик автоматтык түрдө туташтырылбайт"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыш жок"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Башка тармактар жеткиликсиз"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Тармактар жеткиликтүү эмес"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Тармактарды көрүү үчүн кулпусун ачыңыз"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> төмөнкү ыкчам баскычты Ыкчам жөндөөлөргө кошкону жатат"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ыкчам баскыч кошуу"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ыкчам баскыч кошулбасын"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index ea456d8..ac4dfd2 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -28,9 +28,6 @@
     <!-- The number of columns that the top level tiles span in the QuickSettings -->
     <integer name="quick_settings_user_time_settings_tile_span">2</integer>
 
-    <!-- We have only space for one notification on phone landscape layouts. -->
-    <integer name="keyguard_max_notification_count">1</integer>
-
     <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
     <integer name="navigation_bar_deadzone_orientation">1</integer>
 
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index ee0e4b3..fc5edf3 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -41,7 +41,7 @@
     <dimen name="battery_detail_graph_space_top">9dp</dimen>
     <dimen name="battery_detail_graph_space_bottom">9dp</dimen>
 
-    <dimen name="qs_detail_margin_top">14dp</dimen>
+    <dimen name="qs_detail_header_margin_top">14dp</dimen>
 
     <dimen name="volume_tool_tip_top_margin">12dp</dimen>
     <dimen name="volume_row_slider_height">128dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index d2ac9ef..509a6f8 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ປິດການນຳໃຊ້ Smart Lock ແລ້ວ"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ໃຊ້ລາຍນິ້ວມືເພື່ອເປີດ"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ຕ້ອງພິສູດຢືນຢັນ. ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມືເພື່ອພິສູດຢືນຢັນ."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ສາຍໂທອອກ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ໂໝດຢູ່ໃນຍົນ"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ອິນເຕີເນັດມືຖື"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ຈະບໍ່ເຊື່ອມຕໍ່ອິນເຕີເນັດອັດຕະໂນມັດ"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"ຈະບໍ່ເຊື່ອມຕໍ່ອິນເຕີເນັດມືຖືອັດຕະໂນມັດ"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ບໍ່ມີການເຊື່ອມຕໍ່"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ບໍ່ມີເຄືອຂ່າຍອື່ນທີ່ສາມາດໃຊ້ໄດ້"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ບໍ່​ມ​ີ​ເຄືອ​ຂ່າຍ​ທີ່​ສາ​ມາດ​ໃຊ້​ໄດ້"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ປົດລັອກເພື່ອເບິ່ງເຄືອຂ່າຍ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ຕ້ອງການເພີ່ມແຜ່ນຕໍ່ໄປນີ້ໃສ່ການຕັ້ງຄ່າດ່ວນ"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ເພີ່ມແຜ່ນ"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ຢ່າເພີ່ມແຜ່ນ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 3101235..87d67b7 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Keisti mast., kad atit. ekr."</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ištempti, kad atit. ekr."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrano kopija"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"„Smart Lock“ išjungta"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Išsaugoma ekrano kopija..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Naudokite kontrolinį kodą, kad atidarytumėte"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Reikia nustatyti tapatybę. Nustatykite tapatybę palietę kontrolinio kodo jutiklį."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Vykstantis telefono skambutis"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Lėktuvo režimas"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiliojo ryšio duomenys"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Prisijungta"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Prie interneto nebus jungiamasi automatiškai"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Naud. mob. r. duomenis nebus autom. prisijungiama"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nėra ryšio"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nėra kitų pasiekiamų tinklų"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nėra pasiekiamų tinklų"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Atrakinkite, kad peržiūrėtumėte visus tinklus"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ nori prie sparčiųjų nustatymų pridėti toliau pateiktą išklotinės elementą"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridėti išklotinės elementą"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridėti išklotinės elemento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 9c58eaf..242d6ba 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Tālumm., lai aizp. ekr."</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Stiepiet, lai aizp. ekr."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrānuzņēmums"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Sistēma Smart Lock ir atspējota"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saglabā ekrānuzņēmumu…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string>
@@ -184,6 +185,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>
@@ -1165,18 +1168,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Atvēršanai izmantojiet pirksta nospiedumu"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Nepieciešama autentifikācija. Pieskarieties pirksta nospieduma sensoram, lai veiktu autentificēšanu."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Notiekošs tālruņa zvans"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Lidojuma režīms"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilie dati"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Ir izveidots savienojums"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Interneta savienojums netiks izveidots automātiski"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilo datu savienojums netiks veidots automātiski"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nav savienojuma"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nav pieejams neviens cits tīkls"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nav pieejams neviens tīkls"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lai skatītu tīklus, atbloķējiet"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> pieprasa atļauju pievienot tālāk norādīto elementu ātrajiem iestatījumiem"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pievienot elementu"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepievienot elementu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index fc14cba..fe4040e 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај да се исполни екранот"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Растегни да се исполни екранот"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Слика од екранот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Оневозможено е Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"испрати слика"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сликата на екранот се зачувува..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Сликата на екранот се зачувува..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Користете отпечаток за да се отвори"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна е проверка. Допрете го сензорот за отпечаток за да автентицирате."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Тековен телефонски повик"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Авионски режим"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилен интернет"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Поврзано"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Не може автоматски да се поврзе на интернет"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилниот интернет не може автоматски да се поврзе"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Нема интернет-врска"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нема други достапни мрежи"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Нема достапни мрежи"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отклучете за да се прикажат мрежите"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> сака да ја додаде следнава плочка на „Брзите поставки“"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додајте плочка"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додавајте плочка"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 4f90802..db170de 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
@@ -132,7 +133,7 @@
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"ഉപയോഗസഹായി"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"സ്‌ക്രീൻ തിരിക്കുക"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"അവലോകനം"</string>
-    <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+    <string name="accessibility_search_light" msgid="524741790416076988">"തിരയൽ"</string>
     <string name="accessibility_camera_button" msgid="2938898391716647247">"ക്യാമറ"</string>
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ഫോണ്‍"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"വോയ്‌സ് സഹായം"</string>
@@ -184,6 +185,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>
@@ -439,7 +442,7 @@
     <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"ഫുൾ ചാർജാകാൻ, <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
     <string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
     <string name="ssl_ca_cert_warning" msgid="8373011375250324005">"നെറ്റ്‌വർക്ക്\nനിരീക്ഷിക്കപ്പെടാം"</string>
-    <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+    <string name="description_target_search" msgid="3875069993128855865">"തിരയൽ"</string>
     <string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായി മുകളിലേയ്‌ക്ക് സ്ലൈഡുചെയ്യുക."</string>
     <string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായി ഇടത്തേയ്‌ക്ക് സ്ലൈഡുചെയ്യുക."</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"നിങ്ങൾ സജ്ജീകരിച്ച അലാറങ്ങൾ, റിമൈൻഡറുകൾ, ഇവന്റുകൾ, കോളർമാർ എന്നിവയിൽ നിന്നുള്ള ശബ്‌ദങ്ങളും വൈബ്രേഷനുകളുമൊഴികെ മറ്റൊന്നും നിങ്ങളെ ശല്യപ്പെടുത്തുകയില്ല. സംഗീതം, വീഡിയോകൾ, ഗെയിമുകൾ എന്നിവയുൾപ്പെടെ പ്ലേ ചെയ്യുന്നതെന്തും നിങ്ങൾക്ക് ‌തുടർന്നും കേൾക്കാൻ കഴിയും."</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"തുറക്കുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. പരിശോധിച്ചുറപ്പിക്കാൻ, വിരലടയാള സെൻസറിൽ സ്‌പർശിക്കുക."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"സജീവമായ ഫോൺ കോൾ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ഫ്ലൈറ്റ് മോഡ്"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"മൊബൈൽ ഡാറ്റ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"കണക്റ്റ് ചെയ്തു"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ഇന്റർനെറ്റ് സ്വയമേവ കണക്‌റ്റ് ചെയ്യില്ല"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"മൊബൈൽ ഡാറ്റ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"കണക്ഷനില്ല"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"മറ്റ് നെറ്റ്‌വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"നെറ്റ്‌വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"നെറ്റ്‌വർക്കുകൾ കാണാൻ അൺ‌ലോക്ക് ചെയ്യുക"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ദ്രുത ക്രമീകരണത്തിലേക്ക് ഇനിപ്പറയുന്ന ടൈൽ ചേർക്കാൻ <xliff:g id="APPNAME">%1$s</xliff:g> ആവശ്യപ്പെടുന്നു"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ടൈൽ ചേർക്കുക"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ടൈൽ ചേർക്കരുത്"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b079d86..aed89bb 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Дэлгэц дүүргэх бол өсгөнө үү"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Дэлгэц дүүргэх бол татна уу"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Ухаалаг түгжээг идэвхгүй болгосон"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Дэлгэцийн агшинг хадгалж байна…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string>
@@ -184,6 +185,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>
@@ -656,7 +659,7 @@
     <string name="system_ui_tuner" msgid="1471348823289954729">"Системийн UI Тохируулагч"</string>
     <string name="show_battery_percentage" msgid="6235377891802910455">"Залгаатай тэжээлийн хувийг харуулах"</string>
     <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Тэжээлийн хувийг цэнэглээгүй байх үед статусын хэсэгт харуулна уу"</string>
-    <string name="quick_settings" msgid="6211774484997470203">"Түргэвчилсэн Tохиргоо"</string>
+    <string name="quick_settings" msgid="6211774484997470203">"Шуурхай тохиргоо"</string>
     <string name="status_bar" msgid="4357390266055077437">"Статус самбар"</string>
     <string name="overview" msgid="3522318590458536816">"Тойм"</string>
     <string name="demo_mode" msgid="263484519766901593">"Системийн UI демо горим"</string>
@@ -681,7 +684,7 @@
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
     <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> цагт"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-т"</string>
-    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Түргэн Тохиргоо, <xliff:g id="TITLE">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Шуурхай тохиргоо, <xliff:g id="TITLE">%s</xliff:g>."</string>
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Сүлжээний цэг"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"Ажлын профайл"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"Зарим хүнд хөгжилтэй байж болох ч бүх хүнд тийм биш"</string>
@@ -694,8 +697,8 @@
     <string name="activity_not_found" msgid="8711661533828200293">"Аппыг таны төхөөрөмжид суулгаагүй байна"</string>
     <string name="clock_seconds" msgid="8709189470828542071">"Цагийн секундыг харуулах"</string>
     <string name="clock_seconds_desc" msgid="2415312788902144817">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
-    <string name="qs_rearrange" msgid="484816665478662911">"Түргэн тохиргоог дахин засварлах"</string>
-    <string name="show_brightness" msgid="6700267491672470007">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
+    <string name="qs_rearrange" msgid="484816665478662911">"Шуурхай тохиргоог дахин засварлах"</string>
+    <string name="show_brightness" msgid="6700267491672470007">"Шуурхай тохиргоонд гэрэлтүүлэг харах"</string>
     <string name="experimental" msgid="3549865454812314826">"Туршилтын"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"Bluetooth-г асаах уу?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
@@ -917,11 +920,11 @@
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Хавтан нэмсэн"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Хавтанг хассан"</string>
-    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Түргэн тохиргоо засварлагч."</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Шуурхай тохиргоо засварлагч."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> мэдэгдэл: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Тохиргоог нээнэ үү."</string>
     <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Шуурхай тохиргоог нээнэ үү."</string>
-    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Хурдан тохиргоог хаана уу."</string>
+    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Шуурхай тохиргоог хаана уу."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Сэрүүлэг тавьсан."</string>
     <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g>-р нэвтэрсэн"</string>
     <string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"хэрэглэгчийг сонгох"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Нээхийн тулд хурууны хээг ашиглана уу"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Баталгаажуулалт шаардлагатай. Баталгаажуулахын тулд хурууны хээ мэдрэгчид хүрнэ үү."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Үргэлжилж буй утасны дуудлага"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Нислэгийн горим"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобайл дата"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Холбогдсон"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Интернэт автоматаар холбогдохгүй"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобайл дата автоматаар холбогдохгүй"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Холболт алга"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Өөр боломжтой сүлжээ байхгүй байна"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Боломжтой сүлжээ байхгүй байна"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Сүлжээг харахын тулд түгжээг тайлах"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> нь дараах хавтанг Шуурхай тохиргоонд нэмэх хүсэлтэй байна"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Хавтан нэмэх"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Хавтанг бүү нэм"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 0e8de95..633519a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock बंद केले"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
@@ -132,7 +133,7 @@
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"अ‍ॅक्सेसिबिलिटी"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"स्क्रीन फिरवा"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"अवलोकन"</string>
-    <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+    <string name="accessibility_search_light" msgid="524741790416076988">"शोधा"</string>
     <string name="accessibility_camera_button" msgid="2938898391716647247">"कॅमेरा"</string>
     <string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"व्हॉइस सहाय्य"</string>
@@ -148,7 +149,7 @@
     <string name="voice_assist_label" msgid="3725967093735929020">"व्हॉइस सहाय्य उघडा"</string>
     <string name="camera_label" msgid="8253821920931143699">"कॅमेरा उघडा"</string>
     <string name="cancel" msgid="1089011503403416730">"रद्द करा"</string>
-    <string name="biometric_dialog_confirm" msgid="2005978443007344895">"खात्री करा"</string>
+    <string name="biometric_dialog_confirm" msgid="2005978443007344895">"कंफर्म करा"</string>
     <string name="biometric_dialog_try_again" msgid="8575345628117768844">"पुन्हा प्रयत्न करा"</string>
     <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ऑथेंटिकेशन रद्द करण्यासाठी टॅप करा"</string>
     <string name="biometric_dialog_face_icon_description_idle" msgid="4351777022315116816">"कृपया पुन्हा प्रयत्न करा"</string>
@@ -184,6 +185,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>
@@ -439,7 +442,7 @@
     <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण होईपर्यंत"</string>
     <string name="expanded_header_battery_not_charging" msgid="809409140358955848">"चार्ज होत नाही"</string>
     <string name="ssl_ca_cert_warning" msgid="8373011375250324005">"नेटवर्कचे परीक्षण\nकेले जाऊ शकते"</string>
-    <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+    <string name="description_target_search" msgid="3875069993128855865">"शोध"</string>
     <string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी वर स्लाइड करा."</string>
     <string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी डावीकडे स्लाइड करा."</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"अलार्म, रिमाइंडर, इव्‍हेंट आणि तुम्ही निश्चित केलेल्या कॉलर व्यतिरिक्त तुम्हाला कोणत्याही आवाज आणि कंपनांचा व्यत्त्यय आणला जाणार नाही. तरीही तुम्ही प्ले करायचे ठरवलेले कोणतेही संगीत, व्हिडिओ आणि गेमचे आवाज ऐकू शकतात."</string>
@@ -551,7 +554,7 @@
     <string name="disable_vpn" msgid="482685974985502922">"VPN अक्षम करा"</string>
     <string name="disconnect_vpn" msgid="26286850045344557">"VPN डिस्कनेक्ट करा"</string>
     <string name="monitoring_button_view_policies" msgid="3869724835853502410">"धोरणे पहा"</string>
-    <string name="monitoring_button_view_controls" msgid="8316440345340701117">"नियंत्रणे पाहा"</string>
+    <string name="monitoring_button_view_controls" msgid="8316440345340701117">"नियंत्रणे पहा"</string>
     <string name="monitoring_description_named_management" msgid="505833016545056036">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> चे आहे.\n\nतुमचा आयटी ॲडमिन सेटिंग्ज, कॉर्पोरेट अ‍ॅक्सेस, ॲप्‍स, तुमच्‍या डिव्‍हाइसशी संबंधित डेटा आणि तुमच्‍या डिव्‍हाइसच्‍या स्‍थानाची माहिती यांचे परीक्षण व व्‍यवस्‍थापन करू शकतो.\n\nअधिक माहितीसाठी तुमच्‍या आयटी ॲडमिनशी संपर्क साधा."</string>
     <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> कदाचित या डिव्हाइसशी संलग्न असलेला डेटा अ‍ॅक्सेस करू शकते, ॲप्सचे व्यवस्थापन करू शकते आणि ही डिव्हाइस सेटिंग्ज बदलू शकते.\n\nतुम्हाला प्रश्न असल्यास, <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g> शी संपर्क साधा."</string>
     <string name="monitoring_description_management" msgid="4308879039175729014">"हे डिव्हाइस तुमच्या संस्थेचे आहे.\n\nतुमचा आयटी ॲडमिन सेटिंग्ज, कॉर्पोरेट अ‍ॅक्सेस, ॲप्‍स, तुमच्‍या डिव्‍हाइसशी संबंधित डेटा आणि तुमच्‍या डिव्‍हाइसच्‍या स्‍थानाची माहिती यांचे परीक्षण व व्‍यवस्‍थापन करू शकतो.\n\nअधिक माहितीसाठी तुमच्‍या आयटी ॲडमिनशी संपर्क साधा."</string>
@@ -649,7 +652,7 @@
     <string name="output_title" msgid="3938776561655668350">"मीडिया आउटपुट"</string>
     <string name="output_calls_title" msgid="7085583034267889109">"फोन कॉल आउटपुट"</string>
     <string name="output_none_found" msgid="5488087293120982770">"कोणतीही डिव्हाइस सापडली नाहीत"</string>
-    <string name="output_none_found_service_off" msgid="935667567681386368">"कोणतीही डिव्हाइस सापडली नाहीत. <xliff:g id="SERVICE">%1$s</xliff:g> सुरू करून पाहा"</string>
+    <string name="output_none_found_service_off" msgid="935667567681386368">"कोणतीही डिव्हाइस सापडली नाहीत. <xliff:g id="SERVICE">%1$s</xliff:g> सुरू करून पहा"</string>
     <string name="output_service_bt" msgid="4315362133973911687">"ब्लूटूथ"</string>
     <string name="output_service_wifi" msgid="9003667810868222134">"वाय-फाय"</string>
     <string name="output_service_bt_wifi" msgid="7186882540475524124">"ब्लूटूथ आणि वाय-फाय"</string>
@@ -752,7 +755,7 @@
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"या सूचनांचा संच येथे कॉंफिगर केला जाऊ शकत नाही"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"प्रॉक्सी केलेल्या सूचना"</string>
     <string name="notification_channel_dialog_title" msgid="6856514143093200019">"सर्व <xliff:g id="APP_NAME">%1$s</xliff:g> वरील सूचना"</string>
-    <string name="see_more_title" msgid="7409317011708185729">"आणखी पाहा"</string>
+    <string name="see_more_title" msgid="7409317011708185729">"आणखी पहा"</string>
     <string name="appops_camera" msgid="5215967620896725715">"हे अ‍ॅप कॅमेरा वापरत आहे."</string>
     <string name="appops_microphone" msgid="8805468338613070149">"हे अ‍ॅप मायक्रोफोन वापरत आहे."</string>
     <string name="appops_overlay" msgid="4822261562576558490">"हे अ‍ॅप स्क्रीनवरील इतर अ‍ॅप्स वर प्रदर्शित होत आहे."</string>
@@ -936,14 +939,14 @@
     <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_help_text" msgid="6413474593462902901">"काय काळजी घ्यावी ते पाहा"</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>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
-    <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पाहा"</string>
+    <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पहा"</string>
     <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग करा"</string>
     <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"हे डिव्हाइस चार्ज करताना समस्या आहे. पॉवर अडॅप्टर अनप्लग करा आणि शक्य तेवढी काळजी घ्या कदाचित केबल गरम असू शकते."</string>
-    <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"काय काळजी घ्यावी ते पाहा"</string>
+    <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"काय काळजी घ्यावी ते पहा"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"डावा शॉर्टकट"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"उजवा शॉर्टकट"</string>
     <string name="lockscreen_unlock_left" msgid="1417801334370269374">"डावा शॉर्टकट देखील अनलॉक करतो"</string>
@@ -1011,7 +1014,7 @@
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ऑफिस)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"फोन कॉल"</string>
     <string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> द्वारे)"</string>
-    <string name="privacy_type_camera" msgid="7974051382167078332">"कॅमेरा"</string>
+    <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
     <string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
     <string name="privacy_type_microphone" msgid="9136763906797732428">"मायक्रोफोन"</string>
     <string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सर बंद आहेत"</string>
@@ -1033,7 +1036,7 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फुल स्क्रीन मॅग्निफाय करा"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच करा"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"अ‍ॅक्सेसिबिलिटी जेश्चर हे आता अ‍ॅक्सेसिबिलिटी बटण आहे \n\n"<annotation id="link">"सेटिंग्ज पाहा"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"अ‍ॅक्सेसिबिलिटी जेश्चर हे आता अ‍ॅक्सेसिबिलिटी बटण आहे \n\n"<annotation id="link">"सेटिंग्ज पहा"</annotation></string>
     <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"तुम्ही अ‍ॅक्सेसिबिलिटी जेश्चरवरून बटणवर स्विच करू शकता \n\n"<annotation id="link">"सेटिंग्ज"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्‍यामध्ये हलवा"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string>
@@ -1142,7 +1145,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"उघडण्यासाठी फिंगरप्रिंट वापरा"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ऑथेंटिकेशन आवश्यक आहे. ऑथेंटिकेट करण्यासाठी फिंगरप्रिंट सेन्सरला स्पर्श करा."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"फोन कॉल सुरू आहे"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"विमान मोड"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट केले आहे"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"इंटरनेट ऑटो-कनेक्ट होणार नाही"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"कोणतेही कनेक्शन नाही"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"इतर कोणतेही नेटवर्क उपलब्ध नाहीत"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"कोणतेही नेटवर्क उपलब्‍ध नाही"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्क पाहण्यासाठी स्क्रीन अनलॉक करा"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ला क्विक सेटिंग्जमध्ये पुढील टाइल जोडायची आहे"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोडा"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल जोडू नका"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 955754a..a689bb3 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zum untuk memenuhi skrin"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Regang utk memenuhi skrin"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dilumpuhkan"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan tangkapan skrin..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan cap jari untuk membuka"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Pengesahan diperlukan. Sentuh penderia cap jari untuk pengesahan."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Panggilan telefon yang sedang berjalan"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Mod pesawat"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data mudah alih"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Disambungkan"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet tidak akan bersambung secara automatik"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data mudah alih tidak akan autosambung"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Tiada sambungan"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Tiada rangkaian lain yang tersedia"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Tiada rangkaian tersedia"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat rangkaian"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> mahu menambah jubin yang berikut kepada Tetapan Pantas"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan jubin"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah jubin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 968f6db..4975a0a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ဇူးမ်အပြည့်ဆွဲခြင်း"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ဖန်သားပြင်အပြည့်ဆန့်ခြင်း"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ပိတ်ထားသည်"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ဖန်သားပြင်ဓါတ်ပုံသိမ်းစဉ်.."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ဖွင့်ရန် လက်ဗွေကို သုံးပါ"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"အထောက်အထားစိစစ်ခြင်း လိုအပ်သည်။ အထောက်အထားစိစစ်ရန် လက်ဗွေ အာရုံခံကိရိယာကို ထိပါ။"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"လက်ရှိ ဖုန်းခေါ်ဆိုမှု"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"လေယာဉ်ပျံမုဒ်"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"အင်တာနက်က အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"မိုဘိုင်းဒေတာက အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ချိတ်ဆက်မှုမရှိပါ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"အခြားကွန်ရက်များ မရှိပါ"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ကွန်ရက်များ မရှိပါ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ကွန်ရက်များကြည့်ရန် ဖွင့်ပါ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> က ‘အမြန် ဆက်တင်များ’ တွင် အောက်ပါအကွက်ငယ်ကို ထည့်လိုသည်"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"အကွက်ငယ် ထည့်ရန်"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"အကွက်ငယ် မထည့်ပါ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1f8a01b..af8d47b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom for å fylle skjermen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Strekk for å fylle skjerm"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock er slått av"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Lagrer skjermdumpen …"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Bruk fingeravtrykk for å åpne"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering kreves. Trykk på fingeravtrykkssensoren for å autentisere."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående telefonsamtale"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Flymodus"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Tilkoblet"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internett kobles ikke til automatisk"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobildata kobler ikke til automatisk"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen tilkobling"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ingen andre nettverk er tilgjengelige"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Ingen nettverk er tilgjengelige"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil legge til denne brikken i Hurtiginnstillinger"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Legg til brikke"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ikke legg til brikke"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 979d0c7..b6a186e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"स्मार्ट लक अफ गरिएको छ"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि गर्नु पर्ने हुन्छ। पुष्टि गर्न फिंगरप्रिन्ट सेन्सर छुनुहोस्।"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"जारी फोन कल"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"हवाइजहाज मोड"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"इन्टरनेट स्वतः कनेक्ट हुँदैन"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा स्वतः कनेक्ट हुँदैन"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"इन्टरनेट छैन"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"अन्य नेटवर्क उपलब्ध छैनन्"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"कुनै पनि नेटवर्क उपलब्ध छैन"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्कहरू हेर्न आफ्नो स्क्रिन अनलक गर्नुहोस्"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> द्रुत सेटिङमा निम्न टाइल हाल्न चाहन्छ"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल हाल्नुहोस्"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल नहाल्नुहोस्"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index e751512..135ca57 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom om scherm te vullen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rek uit v. schermvulling"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock staat uit"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"heeft een afbeelding gestuurd"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot opslaan..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot opslaan..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om te openen"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Verificatie vereist. Raak de vingerafdruksensor aan om de verificatie uit te voeren."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Actief telefoongesprek"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Vliegtuigmodus"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Verbonden"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet maakt niet automatisch verbinding"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data maakt niet automatisch verbinding"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen andere netwerken beschikbaar"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Geen netwerken beschikbaar"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontgrendel het scherm om netwerken te bekijken"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil de volgende tegel toevoegen aan Snelle instellingen"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tegel toevoegen"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tegel niet toevoegen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 5763a34..1d5ff4b 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ସ୍କ୍ରୀନ୍‌କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍‌ସଟ୍ ନିଅନ୍ତୁ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ସ୍ମାର୍ଟ ଲକ୍ ଅକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
@@ -132,7 +133,7 @@
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"ଆକ୍ସେସିବିଲିଟୀ"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"ସ୍କ୍ରୀନ୍‌କୁ ଘୁରାନ୍ତୁ"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"ଓଭରଭିଉ"</string>
-    <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+    <string name="accessibility_search_light" msgid="524741790416076988">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="accessibility_camera_button" msgid="2938898391716647247">"କ୍ୟାମେରା"</string>
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ଫୋନ୍‍"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ଭଏସ୍‌ ସହାୟକ"</string>
@@ -184,6 +185,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>
@@ -245,7 +248,7 @@
     <skip />
     <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_quick_settings" msgid="4374766941484719179">"କ୍ୱିକ୍ ସେଟିଂସ୍।"</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍‌ ସ୍କ୍ରୀନ୍‌।"</string>
     <string name="accessibility_desc_settings" msgid="6728577365389151969">"ସେଟିଂସ୍"</string>
     <string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀ"</string>
@@ -439,7 +442,7 @@
     <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବାକୁ ଆଉ <xliff:g id="CHARGING_TIME">%s</xliff:g> ଅଛି"</string>
     <string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
     <string name="ssl_ca_cert_warning" msgid="8373011375250324005">"ନେଟ୍‍ୱର୍କ\nମନିଟର୍‍ କରାଯାଇପାରେ"</string>
-    <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+    <string name="description_target_search" msgid="3875069993128855865">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
     <string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ପାଇଁ ଉପରକୁ ସ୍ଲାଇଡ୍‍ କରନ୍ତୁ।"</string>
     <string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ପାଇଁ ବାମକୁ ସ୍ଲାଇଡ୍ କରନ୍ତୁ"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"ଆଲାର୍ମ, ରିମାଇଣ୍ଡର୍‌, ଇଭେଣ୍ଟ ଏବଂ ଆପଣ ନିର୍ଦ୍ଦିଷ୍ଟ କରିଥିବା କଲର୍‌ଙ୍କ ବ୍ୟତୀତ ଆପଣଙ୍କ ଧ୍ୟାନ ଅନ୍ୟ କୌଣସି ଧ୍ୱନୀ ଏବଂ ଭାଇବ୍ରେଶନ୍‌ରେ ଆକର୍ଷଣ କରାଯିବନାହିଁ। ମ୍ୟୁଜିକ୍‍, ଭିଡିଓ ଏବଂ ଗେମ୍‌ ସମେତ ନିଜେ ଚଲାଇବାକୁ ବାଛିଥିବା ଅନ୍ୟ ସବୁକିଛି ଆପଣ ଶୁଣିପାରିବେ।"</string>
@@ -656,7 +659,7 @@
     <string name="system_ui_tuner" msgid="1471348823289954729">"ସିଷ୍ଟମ୍ UI ଟ୍ୟୁନର୍‍"</string>
     <string name="show_battery_percentage" msgid="6235377891802910455">"ଏମ୍ବେଡ୍‍ ହୋଇଥିବା ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
     <string name="show_battery_percentage_summary" msgid="9053024758304102915">"ଚାର୍ଜ ହେଉନଥିବାବେଳେ ଷ୍ଟାଟସ୍‍ ବାର୍‍ ଆଇକନ୍‍ ଭିତରେ ବ୍ୟାଟେରୀ ସ୍ତର ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
-    <string name="quick_settings" msgid="6211774484997470203">"ଦ୍ରୁତ ସେଟିଂସ୍"</string>
+    <string name="quick_settings" msgid="6211774484997470203">"କ୍ୱିକ୍ ସେଟିଂସ୍"</string>
     <string name="status_bar" msgid="4357390266055077437">"ଷ୍ଟାଟସ୍‍ ବାର୍‍"</string>
     <string name="overview" msgid="3522318590458536816">"ଅବଲୋକନ"</string>
     <string name="demo_mode" msgid="263484519766901593">"ସିଷ୍ଟମ୍‌ UI ଡେମୋ ମୋଡ୍‌"</string>
@@ -681,7 +684,7 @@
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
     <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ହେଲେ"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string>
-    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ଦ୍ରୁତ ସେଟିଙ୍ଗ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
+    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"କ୍ୱିକ୍ ସେଟିଂସ୍, <xliff:g id="TITLE">%s</xliff:g>।"</string>
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ହଟସ୍ପଟ୍‌"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"କେତେକଙ୍କ ପାଇଁ ମଜାଦାର, କିନ୍ତୁ ସମସ୍ତଙ୍କ ପାଇଁ ନୁହେଁ"</string>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ପ୍ରମାଣୀକରଣ ଆବଶ୍ୟକ। ପ୍ରମାଣୀକରଣ କରିବାକୁ ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ।"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ଚାଲୁଥିବା ଫୋନ୍ କଲ୍"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ଏୟାରପ୍ଲେନ୍ ମୋଡ୍"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ମୋବାଇଲ ଡାଟା"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"ସଂଯୋଗ କରାଯାଇଛି"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ଇଣ୍ଟରନେଟ୍ ସ୍ଵତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ସଂଯୋଗ ନାହିଁ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ଅନ୍ୟ କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ନେଟୱାର୍କଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> କ୍ୱିକ୍ ସେଟିଂସରେ ନିମ୍ନୋକ୍ତ ଟାଇଲ୍ ଯୋଗ କରିବାକୁ ଚାହେଁ"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ଟାଇଲ୍ ଯୋଗ କର ନାହିଁ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0fe6f8a..055d75b 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ਖੋਲ੍ਹਣ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ਪ੍ਰਮਾਣੀਕਰਨ ਲੋੜੀਂਦਾ ਹੈ। ਪ੍ਰਮਾਣਿਤ ਕਰਨ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ।"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ਜਾਰੀ ਫ਼ੋਨ ਕਾਲ"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"ਕਨੈਕਟ ਹੈ"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ਇੰਟਰਨੈੱਟ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ਕੋਈ ਹੋਰ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ਕੋਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅੱਗੇ ਦਿੱਤੀ ਟਾਇਲ ਨੂੰ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ਟਾਇਲ ਸ਼ਾਮਲ ਨਾ ਕਰੋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 220cd80..fc32959 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Powiększ, aby wypełnić ekran"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Rozciągnij, aby wypełnić ekran"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Wyłączono Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Zapisywanie zrzutu ekranu..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Wymagane uwierzytelnienie. Dotknij czytnika liniii papilarnych, by uwierzytelnić."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktywne połączenie"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Tryb samolotowy"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilna transmisja danych"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Połączono"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Nie połączy się automatycznie z internetem"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna transmisja danych nie połączy się automatycznie"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Brak połączenia"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Brak innych dostępnych sieci"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Brak dostępnych sieci"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odblokuj, by wyświetlić sieci"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> chce dodać do Szybkich ustawień ten kafelek"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj kafelek"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nie dodawaj kafelka"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 39911ca..24880122 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"O Smart Lock foi desativado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modo avião"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"A Internet não será conectada automaticamente"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nenhuma rede disponível"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"O app <xliff:g id="APPNAME">%1$s</xliff:g> quer adicionar o bloco a seguir às Configurações rápidas"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index d475e5d..68d306d 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para preencher o ecrã"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Esticar p. caber em ec. int."</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock desativado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"A guardar captura de ecrã..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilize a impressão digital para abrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação necessária. Toque no sensor de impressões digitais para autenticar."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada telefónica em curso"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modo de avião"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Ligado"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"A Internet não estabelece ligação automaticamente"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Não é efetuada ligação de dados móveis automática"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem ligação"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Sem redes disponíveis"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A app <xliff:g id="APPNAME">%1$s</xliff:g> pretende adicionar o seguinte mosaico às Definições rápidas"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar mosaico"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 39911ca..24880122 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"O Smart Lock foi desativado"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modo avião"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"A Internet não será conectada automaticamente"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nenhuma rede disponível"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"O app <xliff:g id="APPNAME">%1$s</xliff:g> quer adicionar o bloco a seguir às Configurações rápidas"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 26a8cce..169108a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zoom pt. a umple ecranul"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Înt. pt. a umple ecranul"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dezactivat"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Se salv. captura de ecran..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string>
@@ -184,6 +185,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>
@@ -1165,18 +1168,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosiți amprenta ca să deschideți"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atingeți senzorul de amprentă pentru a vă autentifica."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Apel telefonic în desfășurare"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modul Avion"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectat"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Nu se conectează automat la internet"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nu se conectează automat la date mobile"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nicio conexiune"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nu sunt disponibile alte rețele"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nicio rețea disponibilă"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblocați pentru a vedea rețelele"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vrea să adauge următorul card la Setări rapide"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adăugați un card"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nu adăugați un card"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 533b81c..1859acd 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Подогнать по размерам экрана"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Растянуть на весь экран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функция Smart Lock отключена."</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сохранение..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Используйте отпечаток пальца для входа."</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Требуется аутентификация. Приложите палец к сканеру отпечатков."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Текущий вызов"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Режим полета"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильный интернет"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Подключено"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Без автоподключения к интернету"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Без автоподключения к мобильному интернету"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Нет подключения к интернету"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нет других доступных сетей"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Нет доступных сетей"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" хочет добавить в меню \"Быстрые настройки\" указанный параметр."</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Добавить параметр"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не добавлять"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 63baa6d..2df39d7 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"තිරය පිරවීමට විශාලනය කරන්න"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"තිරය පිරවීමට අදින්න"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"තිර රුව"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock අබලයි"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"තිර රුව සුරකිමින්…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"විවෘත කිරීමට ඇඟිලි සලකුණ භාවිත කරන්න"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"සත්‍යාපනය අවශ්‍යයි. සත්‍යාපනය කිරීමට ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ක්‍රියාත්මක වන දුරකථන ඇමතුම"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ගුවන් යානා ප්‍රකාරය"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"ජංගම දත්ත"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"සම්බන්ධයි"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"අන්තර්ජාලය ස්වයංක්‍රියව සම්බන්ධ නොවනු ඇත"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"ජංගම දත්ත ස්වංක්‍රියව සම්බන්ධ නොවනු ඇත"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"සම්බන්ධතාවයක් නැත"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ලබා ගත හැකි වෙනත් ජාල නැත"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ජාලය නොතිබේ"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ජාල බැලීමට අගුලු හරින්න"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> හට ක්ෂණික සැකසීම් වෙත පහත ටයිල් එක් කිරීමට අවශ්‍යයි"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ටයිල් එක් කරන්න"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ටයිල් එක් නොකරන්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 3a22085..6ef5ad5 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Priblížiť na celú obrazovku"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Na celú obrazovku"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funkcia Smart Lock je deaktivovaná"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Prebieha ukladanie snímky obrazovky..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorte odtlačkom prsta"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vyžaduje sa overenie. Dotknite sa senzora odtlačkov prstov."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Prebiehajúci telefonický hovor"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Režim v lietadle"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilné dáta"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Pripojené"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet sa nepripojí automaticky"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Automatické pripojenie cez mobilné dáta nefunguje"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bez pripojenia"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nie sú k dispozícii žiadne ďalšie siete"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nie sú k dispozícii žiadne siete"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odomknutím si zobrazte siete"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikácia <xliff:g id="APPNAME">%1$s</xliff:g> chce pridať do rýchlych nastavení túto kartu"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridať kartu"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridať kartu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5b8f826..977104c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Povečava čez cel zaslon"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Raztegnitev čez zaslon"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Storitev Smart Lock je onemogočena."</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Shranjev. posnetka zaslona ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Odprite s prstnim odtisom"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Zahtevano je preverjanje pristnosti. Za preverjanje pristnosti se dotaknite tipala prstnih odtisov."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Poteka klic"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Način za letalo"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Prenos podatkov v mobilnem omrežju"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Samodejna povezava z internetom ni mogoča."</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna podatkovna povezava ne bo samodejna."</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ni povezave"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nobeno drugo omrežje ni na voljo"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Na voljo ni nobeno omrežje"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odklenite za ogled omrežij"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> želi dodati to ploščico v hitre nastavitve."</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj ploščico"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne dodaj ploščice"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 40f77f67..970b84c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock është çaktivizuar"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kërkohet vërtetimi. Prek sensorin e gjurmës së gishtit për t\'u vërtetuar."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonatë në vazhdim"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Modaliteti i aeroplanit"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Interneti nuk do të lidhet automatikisht"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nuk ka lidhje"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nuk ofrohet asnjë rrjet tjetër"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nuk ofrohet asnjë rrjet"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Shkyçe për të parë rrjetet"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> dëshiron të shtojë pllakëzën e mëposhtme te \"Cilësimet e shpejta\""</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Shto një pllakëz"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mos e shto pllakëzën"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e5ec321..e83b423 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај на целом екрану"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Развуци на цео екран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Снимак екрана"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock је онемогућен"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Чување снимка екрана..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string>
@@ -184,6 +185,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>
@@ -1011,7 +1014,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликације користе <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
     <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
-    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Користи <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+    <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Користи: <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Недавно користио/ла <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(посао)"</string>
     <string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонски позив"</string>
@@ -1165,18 +1168,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Отворите помоћу отиска прста"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна је потврда идентитета. Додирните сензор за отисак прста да бисте потврдили идентитет."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Актуелни телефонски позив"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Режим рада у авиону"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни подаци"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Повезано"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Аутоматско повезивање на интернет није могуће"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Није успело аутом. повезивање преко моб. података"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Веза није успостављена"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Није доступна ниједна друга мрежа"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Нема доступних мрежа"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Откључајте да бисте видели мреже"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> жели да дода следећу плочицу у Брза подешавања"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додај плочицу"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додај плочицу"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e7b41f5..bd819e5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Zooma för att fylla skärm"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Dra för att fylla skärmen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skärmbild"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock har inaktiverats"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skärmbilden sparas ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmbilden sparas ..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Öppna med fingeravtryck"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering krävs. Identifiera dig genom att trycka på fingeravtryckssensorn."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående samtal"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Flygplansläge"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Ansluten"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Du ansluts inte automatiskt till internet"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Du ansluts inte till mobildata automatiskt"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen anslutning"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Inga andra nätverk är tillgängliga"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Det finns inga tillgängliga nätverk"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås upp för att visa nätverk"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vill lägga till följande ruta i snabbinställningarna"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lägg till ruta"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Lägg inte till ruta"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index f58abab..121bcd2 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Kuza ili kujaza skrini"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Tanua ili kujaza skrini"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Kipengele cha Smart Lock kimezimwa"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Tumia alama ya kidole kufungua"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Uthibitishaji unahitajika. Gusa kitambua alama ya kidole ili uthibitishe."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Simu inayoendelea"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Hali ya ndegeni"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data ya mtandao wa simu"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Imeunganishwa"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Intaneti haitaunganishwa kiotomatiki"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data ya mtandao wa simu haitaunganishwa kiotomatiki"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Hakuna muunganisho"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Hakuna mitandao mingine inayopatikana"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Hakuna mitandao inayopatikana"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Fungua ili uangalie mitandao"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ingependa kuongeza kigae kifuatacho kwenye Mipangilio ya Haraka"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ongeza kigae"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Usiongeze kigae"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 527537b..d921d49 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -100,4 +100,10 @@
     same as phones in portrait  -->
     <dimen name="qs_security_footer_single_line_height">48dp</dimen>
     <dimen name="qs_security_footer_background_inset">0dp</dimen>
+
+    <!-- When split shade is used, this panel should be aligned to the top -->
+    <dimen name="qs_detail_margin_top">0dp</dimen>
+
+    <!-- Internet panel related dimensions -->
+    <dimen name="internet_dialog_list_max_width">624dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index 64e2760e..436f8d0 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,8 +22,5 @@
 <resources>
     <integer name="status_bar_config_maxNotificationIcons">5</integer>
 
-    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
-         card. -->
-    <integer name="keyguard_max_notification_count">5</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index ac21044..74bdd32 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"திரையை நிரப்ப அளவை மாற்று"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"திரையை நிரப்ப இழு"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock முடக்கப்பட்டது"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
@@ -122,10 +123,10 @@
     <string name="screenrecord_delete_error" msgid="2870506119743013588">"திரை ரெக்கார்டிங்கை நீக்குவதில் பிழை"</string>
     <string name="screenrecord_permission_error" msgid="7856841237023137686">"அனுமதிகளைப் பெற இயலவில்லை"</string>
     <string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string>
-    <string name="usb_preference_title" msgid="1439924437558480718">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
+    <string name="usb_preference_title" msgid="1439924437558480718">"USB ஃபைல் இடமாற்ற விருப்பங்கள்"</string>
     <string name="use_mtp_button_title" msgid="5036082897886518086">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
     <string name="use_ptp_button_title" msgid="7676427598943446826">"(PTP) கேமராவாக ஏற்று"</string>
-    <string name="installer_cd_button_title" msgid="5499998592841984743">"Mac க்கான Android கோப்பு இடமாற்ற ஆப்ஸை நிறுவு"</string>
+    <string name="installer_cd_button_title" msgid="5499998592841984743">"Mac க்கான Android ஃபைல் இடமாற்ற ஆப்ஸை நிறுவு"</string>
     <string name="accessibility_back" msgid="6530104400086152611">"பின்செல்"</string>
     <string name="accessibility_home" msgid="5430449841237966217">"முகப்பு"</string>
     <string name="accessibility_menu" msgid="2701163794470513040">"மெனு"</string>
@@ -184,6 +185,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>
@@ -449,7 +452,7 @@
     <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="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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"கைரேகையைப் பயன்படுத்தி திறந்திடுங்கள்"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"அங்கீகாரம் தேவை. கைரேகை சென்சாரைத் தொட்டு அங்கீகரியுங்கள்."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"செயலில் உள்ள மொபைல் அழைப்பு"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"விமானப் பயன்முறை"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"மொபைல் டேட்டா"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"இணைக்கப்பட்டது"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"இணையத்துடன் தானாகவே இணைக்காது"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"மொபைல் டேட்டாவுடன் தானாக இணைக்காது"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"இணைப்பு இல்லை"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"வேறு நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"விரைவு அமைப்புகளில் பின்வரும் கட்டத்தைச் சேர்க்க <xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸ் விரும்புகிறது"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"கட்டத்தைச் சேர்"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"கட்டத்தை சேர்க்காதே"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-ldrtl/strings.xml b/packages/SystemUI/res/values-te-ldrtl/strings.xml
index 1c1b562..94bdbcf 100644
--- a/packages/SystemUI/res/values-te-ldrtl/strings.xml
+++ b/packages/SystemUI/res/values-te-ldrtl/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"యాప్‌లను శీఘ్రంగా స్విచ్ చేయడానికి ఎడమ వైపుకు లాగండి"</string>
+    <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"యాప్‌లను శీఘ్రంగా స్విచ్ చేయడానికి ఎడమ వైపునకు లాగండి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ff3f02c..b643685 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -54,7 +54,7 @@
     <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
     <string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"ఈ USB ఉపకరణంతో ఇన్‌స్టాల్ చేయబడిన యాప్‌లు ఏవీ పని చేయవు. ఈ ఉపకరణం గురించి <xliff:g id="URL">%1$s</xliff:g>లో మరింత తెలుసుకోండి"</string>
     <string name="title_usb_accessory" msgid="1236358027511638648">"USB ఉపకరణం"</string>
-    <string name="label_view" msgid="6815442985276363364">"వీక్షించండి"</string>
+    <string name="label_view" msgid="6815442985276363364">"చూడండి"</string>
     <string name="always_use_device" msgid="210535878779644679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
     <string name="always_use_accessory" msgid="1977225429341838444">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
     <string name="usb_debugging_title" msgid="8274884945238642726">"USB డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్‌కు నింపేలా జూమ్ చేయండి"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్‌కు నింపేలా విస్తరించండి"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్‌షాట్"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock డిజేబుల్ చేయబడింది"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్‌ను పంపారు"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
@@ -103,7 +104,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>
@@ -113,7 +114,7 @@
     <string name="screenrecord_stop_text" msgid="6549288689506057686">"ఆపడానికి ట్యాప్ చేయండి"</string>
     <string name="screenrecord_stop_label" msgid="72699670052087989">"ఆపివేయి"</string>
     <string name="screenrecord_pause_label" msgid="6004054907104549857">"పాజ్ చేయి"</string>
-    <string name="screenrecord_resume_label" msgid="4972223043729555575">"కొనసాగించు"</string>
+    <string name="screenrecord_resume_label" msgid="4972223043729555575">"కొనసాగించండి"</string>
     <string name="screenrecord_cancel_label" msgid="7850926573274483294">"రద్దు చేయి"</string>
     <string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string>
     <string name="screenrecord_cancel_success" msgid="1775448688137393901">"స్క్రీన్ రికార్డ్ రద్దు చేయబడింది"</string>
@@ -184,6 +185,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>
@@ -272,10 +275,10 @@
     <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"బ్లూటూత్ ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"బ్లూటూత్ ఆన్ చేయబడింది."</string>
-    <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"స్థాన నివేదన ఆఫ్‌లో ఉంది."</string>
-    <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"స్థాన నివేదన ఆన్‌లో ఉంది."</string>
-    <string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"స్థాన నివేదన ఆఫ్ చేయబడింది."</string>
-    <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"స్థాన నివేదన ఆన్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"లొకేషన్ రిపోర్టింగ్ ఆఫ్‌లో ఉంది."</string>
+    <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"లొకేషన్ రిపోర్టింగ్ ఆన్‌లో ఉంది."</string>
+    <string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"లొకేషన్ రిపోర్టింగ్ ఆఫ్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"లొకేషన్ రిపోర్టింగ్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>కి అలారం సెట్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_close" msgid="2974895537860082341">"ప్యానెల్‌ను మూసివేయి."</string>
     <string name="accessibility_quick_settings_more_time" msgid="7646479831704665284">"ఎక్కువ సమయం."</string>
@@ -305,8 +308,8 @@
     <string name="data_usage_disabled_dialog" msgid="7933201635215099780">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు మొబైల్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు చెల్లించాల్సి రావచ్చు."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"పునఃప్రారంభించు"</string>
     <string name="gps_notification_searching_text" msgid="231304732649348313">"GPS కోసం శోధిస్తోంది"</string>
-    <string name="gps_notification_found_text" msgid="3145873880174658526">"స్థానం GPS ద్వారా సెట్ చేయబడింది"</string>
-    <string name="accessibility_location_active" msgid="2845747916764660369">"స్థాన అభ్యర్థనలు సక్రియంగా ఉన్నాయి"</string>
+    <string name="gps_notification_found_text" msgid="3145873880174658526">"లొకేషన్ GPS ద్వారా సెట్ చేయబడింది"</string>
+    <string name="accessibility_location_active" msgid="2845747916764660369">"లొకేషన్ రిక్వెస్ట్‌లు యాక్టివ్‌గా ఉన్నాయి"</string>
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"సెన్సార్‌లు ఆఫ్ యాక్టివ్‌లో ఉంది"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"అన్ని నోటిఫికేషన్‌లను క్లియర్ చేయండి."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
@@ -317,10 +320,10 @@
     <string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"నోటిఫికేషన్ సెట్టింగ్‌లు"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> సెట్టింగ్‌లు"</string>
-    <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"స్క్రీన్ స్వయంచాలకంగా తిప్పబడుతుంది."</string>
+    <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"స్క్రీన్ ఆటోమేటిక్‌గా తిప్పబడుతుంది."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"స్క్రీన్ ల్యాండ్‌స్కేప్ దృగ్విన్యాసంలో లాక్ చేయబడుతుంది."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"స్క్రీన్ పోర్ట్రెయిట్ దృగ్విన్యాసంలో లాక్ చేయబడుతుంది."</string>
-    <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"స్క్రీన్ ఇప్పుడు స్వయంచాలకంగా తిరుగుతుంది."</string>
+    <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"స్క్రీన్ ఇప్పుడు ఆటోమేటిక్‌గా తిరుగుతుంది."</string>
     <string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"స్క్రీన్ ఇప్పుడు ల్యాండ్‌స్కేప్ దృగ్విన్యాసంలో లాక్ చేయబడింది."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"స్క్రీన్ ఇప్పుడు పోర్ట్రెయిట్ దృగ్విన్యాసంలో లాక్ చేయబడింది."</string>
     <string name="dessert_case" msgid="9104973640704357717">"డెజర్ట్ కేస్"</string>
@@ -445,7 +448,7 @@
     <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>
@@ -504,7 +507,7 @@
     <string name="battery_saver_notification_title" msgid="8419266546034372562">"బ్యాటరీ సేవర్ ఆన్‌లో ఉంది"</string>
     <string name="battery_saver_notification_text" msgid="2617841636449016951">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"బ్యాటరీ సేవర్‌ను ఆఫ్ చేయండి"</string>
-    <string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, చెల్లింపు వివరాలు, ఫోటోలు, సందేశాలు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
+    <string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, చెల్లింపు వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్‌ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు,  మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>తో రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
@@ -550,7 +553,7 @@
     <string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA ప్రమాణపత్రాలు"</string>
     <string name="disable_vpn" msgid="482685974985502922">"VPNని నిలిపివేయి"</string>
     <string name="disconnect_vpn" msgid="26286850045344557">"VPNను డిస్‌కనెక్ట్ చేయి"</string>
-    <string name="monitoring_button_view_policies" msgid="3869724835853502410">"విధానాలను వీక్షించండి"</string>
+    <string name="monitoring_button_view_policies" msgid="3869724835853502410">"విధానాలను చూడండి"</string>
     <string name="monitoring_button_view_controls" msgid="8316440345340701117">"నియంత్రణలను చూడండి"</string>
     <string name="monitoring_description_named_management" msgid="505833016545056036">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>కు చెందినది.\n\nసెట్టింగ్‌లను, కార్పొరేట్ యాక్సెస్‌ను, యాప్‌లను, మీ పరికరానికి సంబంధించిన డేటాను, అలాగే మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ IT అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు.\n\nమరింత సమాచారం కోసం, మీ IT అడ్మిన్‌ను సంప్రదించండి."</string>
     <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g>, ఈ పరికరంతో అనుబంధించబడిన డేటాను యాక్సెస్ చేయవచ్చు, యాప్‌లను మేనేజ్ చేయవచ్చు అలాగే ఈ పరికరాల సెట్టింగ్‌లను మార్చవచ్చు.\n\nమీకు ఏవైనా సందేహాలు ఉంటే, <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>ను కాంటాక్ట్ చేయండి."</string>
@@ -558,7 +561,7 @@
     <string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ఈ పరికరంలో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్‌స్టాల్ చేసింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"మీ కార్యాలయ ప్రొఫైల్‌లో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్‌స్టాల్ చేసింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ఈ పరికరంలో ప్రమాణపత్ర అధికారం ఇన్‌స్టాల్ చేయబడింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
-    <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు."</string>
+    <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేశారు."</string>
     <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"మీ అడ్మిన్ నెట్‌వర్క్ లాగింగ్‌ను ఆన్ చేశారు, ఇది మీ వర్క్ ప్రొఫైల్‌లోని ట్రాఫిక్‌ను పర్యవేక్షిస్తుంది కానీ మీ వ్యక్తిగత ప్రొఫైల్‌లో కాదు."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
@@ -566,7 +569,7 @@
     <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"మీ వ్యక్తిగత ప్రొఫైల్ ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
     <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"మీ పరికరం <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ద్వారా నిర్వహించబడుతోంది."</string>
     <string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> మీ పరికరాన్ని నిర్వహించడానికి <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ని ఉపయోగిస్తుంది."</string>
-    <string name="monitoring_description_do_body" msgid="7700878065625769970">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్‌లు, కార్పొరేట్ యాక్సెస్, యాప్‌లు, డేటా మరియు మీ పరికరం యొక్క స్థాన సమాచారాన్ని మీ నిర్వాహకులు పర్యవేక్షించగలరు మరియు నిర్వహించగలరు."</string>
+    <string name="monitoring_description_do_body" msgid="7700878065625769970">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్‌లు, కార్పొరేట్ యాక్సెస్, యాప్‌లు, డేటా మరియు మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు."</string>
     <string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="645149183455573790">"మరింత తెలుసుకోండి"</string>
     <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
@@ -574,8 +577,8 @@
     <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN సెట్టింగ్‌లను తెరవండి"</string>
     <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"విశ్వసనీయ ఆధారాలను తెరువు"</string>
-    <string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
-    <string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్‌నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఇమెయిల్‌లు,యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ డివైజ్ మరియు నెట్‌వర్క్ కార్యకలాపాన్ని పర్యవేక్షించగలదు."</string>
+    <string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేశారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
+    <string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్‌నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఇమెయిల్‌లు,యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ డివైజ్ మరియు నెట్‌వర్క్ యాక్టివిటీని పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు. మీ తల్లి/తండ్రి, మీరు ఉపయోగించే యాప్‌లు, మీ లొకేషన్, అలాగే మీ పరికర వినియోగ వ్యవధి వంటి సమాచారాన్ని చూడగలరు, మేనేజ్ చేయగలరు."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
@@ -629,7 +632,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>
@@ -645,7 +648,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>
@@ -656,7 +659,7 @@
     <string name="system_ui_tuner" msgid="1471348823289954729">"సిస్టమ్ UI ట్యూనర్"</string>
     <string name="show_battery_percentage" msgid="6235377891802910455">"పొందుపరిచిన బ్యాటరీ శాతం చూపు"</string>
     <string name="show_battery_percentage_summary" msgid="9053024758304102915">"ఛార్జింగ్‌లో లేనప్పుడు స్థితి పట్టీ చిహ్నం లోపల బ్యాటరీ స్థాయి శాతం చూపుతుంది"</string>
-    <string name="quick_settings" msgid="6211774484997470203">"శీఘ్ర సెట్టింగ్‌లు"</string>
+    <string name="quick_settings" msgid="6211774484997470203">"క్విక్ సెట్టింగ్‌లు"</string>
     <string name="status_bar" msgid="4357390266055077437">"స్థితి పట్టీ"</string>
     <string name="overview" msgid="3522318590458536816">"ఓవర్‌వ్యూ"</string>
     <string name="demo_mode" msgid="263484519766901593">"సిస్టమ్ UI డెమో మోడ్"</string>
@@ -707,7 +710,7 @@
     <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>
@@ -867,7 +870,7 @@
     <string name="nav_bar_layout" msgid="4716392484772899544">"లేఅవుట్"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"అత్యంత ఎడమ వైపు ఉన్న బటన్ రకం"</string>
     <string name="right_nav_bar_button_type" msgid="4472566498647364715">"అత్యంత కుడివైపు ఉన్న బటన్ రకం"</string>
-    <string name="nav_bar_default" msgid="8386559913240761526">"(డిఫాల్ట్)"</string>
+    <string name="nav_bar_default" msgid="8386559913240761526">"(ఆటోమేటిక్)"</string>
   <string-array name="nav_bar_buttons">
     <item msgid="2681220472659720036">"క్లిప్‌బోర్డ్"</item>
     <item msgid="4795049793625565683">"కీకోడ్"</item>
@@ -898,12 +901,12 @@
     <string name="tuner_time" msgid="2450785840990529997">"సమయం"</string>
   <string-array name="clock_options">
     <item msgid="3986445361435142273">"గంటలు, నిమిషాలు మరియు సెకన్లను చూపు"</item>
-    <item msgid="1271006222031257266">"గంటలు మరియు నిమిషాలను చూపు (డిఫాల్ట్)"</item>
+    <item msgid="1271006222031257266">"గంటలు, నిమిషాలను చూపు (ఆటోమేటిక్)"</item>
     <item msgid="6135970080453877218">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
   </string-array>
   <string-array name="battery_options">
     <item msgid="7714004721411852551">"ఎల్లప్పుడూ శాతాన్ని చూపు"</item>
-    <item msgid="3805744470661798712">"ఛార్జ్ అవుతున్నప్పుడు శాతాన్ని చూపు (డిఫాల్ట్)"</item>
+    <item msgid="3805744470661798712">"ఛార్జ్ అవుతున్నప్పుడు శాతాన్ని చూపు (ఆటోమేటిక్)"</item>
     <item msgid="8619482474544321778">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"తక్కువ ప్రాధాన్యత నోటిఫికేషన్ చిహ్నాలను చూపించు"</string>
@@ -923,23 +926,23 @@
     <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"శీఘ్ర సెట్టింగ్‌లను తెరవండి."</string>
     <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"శీఘ్ర సెట్టింగ్‌లను మూసివేయండి."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"అలారం సెట్ చేయబడింది."</string>
-    <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> వలె సైన్ ఇన్ చేసారు"</string>
+    <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> వలె సైన్ ఇన్ చేశారు"</string>
     <string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"యూజర్‌ను ఎంపిక చేయండి"</string>
     <string name="data_connection_no_internet" msgid="691058178914184544">"ఇంటర్నెట్ లేదు"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"వివరాలను తెరవండి."</string>
     <string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"<xliff:g id="REASON">%s</xliff:g> కారణంగా అందుబాటులో లేదు"</string>
     <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్‌లను తెరవండి."</string>
-    <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"సెట్టింగ్‌ల క్రమాన్ని సవరించండి."</string>
+    <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"సెట్టింగ్‌ల క్రమాన్ని ఎడిట్ చేయండి."</string>
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"పవర్ మెనూ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
     <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>
-    <string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ స్వయంచాలకంగా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
+    <string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ ఆటోమేటిక్‌గా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="high_temp_alarm_title" msgid="2359958549570161495">"ప్లగ్ నుండి ఛార్జర్‌ తీసివేయండి"</string>
     <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ఈ పరికరాన్ని ఛార్జ్ చేయడంలో సమస్య ఉంది. పవర్ అడాప్టర్‌ను ప్లగ్ నుండి తీసివేసి, కేబుల్ ఏమైనా వేడిగా అయితే తగిన జాగ్రత్తలు తీసుకోండి."</string>
@@ -961,7 +964,7 @@
     <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>
+    <string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ మెసేజ్‌లు"</string>
     <string name="notification_channel_storage" msgid="2720725707628094977">"స్టోరేజ్"</string>
     <string name="notification_channel_hints" msgid="7703783206000346876">"సూచనలు"</string>
     <string name="instant_apps" msgid="8337185853050247304">"ఇన్‌స్టంట్ యాప్‌లు"</string>
@@ -976,9 +979,9 @@
     <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ఆఫ్‌లో ఉంది"</string>
     <string name="bt_is_off" msgid="7436344904889461591">"బ్లూటూత్ ఆఫ్‌లో ఉంది"</string>
     <string name="dnd_is_off" msgid="3185706903793094463">"అంతరాయం కలిగించవద్దు ఆఫ్‌లో ఉంది"</string>
-    <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"స్వయంచాలక నియమం (<xliff:g id="ID_1">%s</xliff:g>) ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
+    <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ఆటోమేటిక్‌ నియమం (<xliff:g id="ID_1">%s</xliff:g>) ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
     <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"యాప్ (<xliff:g id="ID_1">%s</xliff:g>) ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
-    <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"స్వయంచాలక నియమం లేదా యాప్ ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
+    <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ఆటోమేటిక్‌ నియమం లేదా యాప్ ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
     <string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> వరకు"</string>
     <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
     <string name="qs_dnd_replace" msgid="7712119051407052689">"భర్తీ చేయి"</string>
@@ -987,7 +990,7 @@
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"మొబైల్ డేటాను ఆఫ్ చేయాలా?"</string>
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"\"<xliff:g id="CARRIER">%s</xliff:g>\" ద్వారా మీకు డేటా లేదా ఇంటర్నెట్‌కు యాక్సెస్ ఉండదు. Wi-Fi ద్వారా మాత్రమే ఇంటర్నెట్ అందుబాటులో ఉంటుంది."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"మీ క్యారియర్"</string>
-    <string name="touch_filtered_warning" msgid="8119511393338714836">"అనుమతి అభ్యర్థనకు ఒక యాప్ అడ్డు తగులుతున్నందున సెట్టింగ్‌లు మీ ప్రతిస్పందనను ధృవీకరించలేకపోయాయి."</string>
+    <string name="touch_filtered_warning" msgid="8119511393338714836">"అనుమతి రిక్వెస్ట్‌కు ఒక యాప్ అడ్డు తగులుతున్నందున సెట్టింగ్‌లు మీ ప్రతిస్పందనను ధృవీకరించలేకపోయాయి."</string>
     <string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించడానికి <xliff:g id="APP_0">%1$s</xliff:g>ని అనుమతించండి?"</string>
     <string name="slice_permission_text_1" msgid="6675965177075443714">"- ఇది <xliff:g id="APP">%1$s</xliff:g> నుండి సమాచారాన్ని చదువుతుంది"</string>
     <string name="slice_permission_text_2" msgid="6758906940360746983">"- ఇది <xliff:g id="APP">%1$s</xliff:g> లోపల చర్యలు తీసుకుంటుంది"</string>
@@ -1142,7 +1145,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ప్రామాణీకరణ అవసరం. ప్రామాణీకరించడానికి వేలిముద్ర సెన్సార్‌ను తాకండి."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ఫోన్ కాల్ జరుగుతోంది"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"విమానం మోడ్"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"మొబైల్ డేటా"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"కనెక్ట్ చేయబడింది"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"ఇంటర్నెట్ ఆటోమెటిక్‌గా కనెక్ట్ అవ్వదు"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"కనెక్షన్ లేదు"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ఇతర నెట్‌వర్క్‌లేవీ అందుబాటులో లేవు"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"నెట్‌వర్క్‌లు అందుబాటులో లేవు"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"నెట్‌వర్క్‌లను చూడటానికి అన్‌లాక్ చేయండి"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"కింది టైల్‌ను క్విక్ సెట్టింగ్‌లకు జోడించడానికి <xliff:g id="APPNAME">%1$s</xliff:g> అనుమతి కోరుతోంది"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"టైల్‌ను జోడించండి"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"టైల్‌ను జోడించవద్దు"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml
index 76c620d..d4bfc4d 100644
--- a/packages/SystemUI/res/values-television/dimens.xml
+++ b/packages/SystemUI/res/values-television/dimens.xml
@@ -44,6 +44,7 @@
     <dimen name="privacy_chip_icon_margin_in_between">9dp</dimen>
     <dimen name="privacy_chip_padding_horizontal">9dp</dimen>
     <dimen name="privacy_chip_icon_size">12dp</dimen>
+    <dimen name="privacy_chip_max_width">51dp</dimen>
     <dimen name="privacy_chip_height">24dp</dimen>
     <dimen name="privacy_chip_min_width">30dp</dimen>
     <dimen name="privacy_chip_radius">12dp</dimen>
diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml
index 0fb7898..6fdf2c4 100644
--- a/packages/SystemUI/res/values-television/styles.xml
+++ b/packages/SystemUI/res/values-television/styles.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog" />
     <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Dialog.Alert" />
 
@@ -25,7 +26,7 @@
 
     <style name="volume_dialog_theme" parent="Theme.SystemUI">
         <item name="android:colorAccent">@color/tv_volume_dialog_accent</item>
-        <item name="android:textColorPrimaryInverse">@color/tv_volume_dialog_accent</item>
+        <item name="androidprv:textColorOnAccent">@color/tv_volume_dialog_accent</item>
         <item name="android:dialogCornerRadius">@dimen/volume_dialog_panel_width_half</item>
     </style>
 
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 13e88c5..b27cd3e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"ขยายจนเต็มหน้าจอ"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"ยืดจนเต็มหน้าจอ"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ปิดใช้ Smart Lock แล้ว"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"กำลังบันทึกภาพหน้าจอ..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ใช้ลายนิ้วมือเพื่อเปิด"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ต้องมีการตรวจสอบสิทธิ์ แตะเซ็นเซอร์ลายนิ้วมือเพื่อตรวจสอบสิทธิ์"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"กำลังโทรอยู่"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"โหมดบนเครื่องบิน"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"อินเทอร์เน็ตมือถือ"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"เชื่อมต่อแล้ว"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"อินเทอร์เน็ตจะไม่เชื่อมต่ออัตโนมัติ"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"อินเทอร์เน็ตมือถือจะไม่เชื่อมต่ออัตโนมัติ"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"ไม่มีการเชื่อมต่อ"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ไม่มีเครือข่ายอื่นๆ ที่พร้อมใช้งาน"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"ไม่มีเครือข่ายที่พร้อมใช้งาน"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"ปลดล็อกเพื่อดูเครือข่าย"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ต้องการเพิ่มชิ้นส่วนต่อไปนี้ในการตั้งค่าด่วน"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"เพิ่มชิ้นส่วน"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ไม่ต้องเพิ่มชิ้นส่วน"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 261f568..11a23f8 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"I-zoom upang punan screen"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"I-stretch upang mapuno screen"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Naka-disable ang Smart Lock"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nagpadala ng larawan"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Sine-save ang screenshot…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Sine-save ang screenshot…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gamitin ang fingerprint para buksan"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kailangan ng pag-authenticate. Pindutin ang sensor para sa fingerprint para mag-authenticate."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Kasalukuyang may tawag sa telepono"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Airplane mode"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Nakakonekta"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Hindi awtomatikong kokonekta ang Internet"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Hindi awtomatikong kokonekta ang mobile data"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Walang koneksyon"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Walang available na iba pang network"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Walang available na network"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"I-unlock para tingnan ang mga network"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Gustong idagdag ng <xliff:g id="APPNAME">%1$s</xliff:g> ang sumusunod na tile sa Mga Mabilisang Setting"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Idagdag ang tile"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Huwag idagdag"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a96c62d..a5c06f1 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Yakınlaştır (ekranı kaplasın)"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Genişlet (ekran kapansın)"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock devre dışı"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ekran görüntüsü kaydediliyor..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmak için parmak izi kullanın"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kimlik doğrulaması gerekiyor. Kimlik doğrulaması için parmak izi sensörüne dokunun."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Devam eden telefon görüşmesi"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Uçak modu"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil veri"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Bağlı"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"İnternete otomatik olarak bağlanmaz"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil veri otomatik olarak bağlanmıyor"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yok"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Kullanılabilir başka ağ yok"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Kullanılabilir ağ yok"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ağları görmek için kilidi açın"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aşağıdaki kartı Hızlı Ayarlar\'a eklemek istiyor"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Kart ekle"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Kart ekleme"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8637ad7..616b0f2 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Масштабув. на весь екран"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Розтягнути на весь екран"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock вимкнено"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Збереження знімка екрана..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string>
@@ -184,6 +185,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>
@@ -1171,18 +1174,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Пройдіть автентифікацію. Для цього торкніться сканера відбитків пальців."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Активний телефонний виклик"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Режим польоту"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Автоматичне інтернет-з’єднання вимкнено"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобільний Інтернет не підключатиметься автоматично"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Немає з\'єднання"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Інші мережі недоступні"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Немає доступних мереж"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Розблокувати, щоб переглянути мережі"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Додаток <xliff:g id="APPNAME">%1$s</xliff:g> хоче додати такий параметр у меню швидких налаштувань:"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додати параметр"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додавати параметр"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4321c3e..a42729e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"پوری سکرین پر زوم کریں"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"پوری سکرین پر پھیلائیں"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"‏Smart Lock کو غیر فعال کیا گیا"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"توثیق مطلوب ہے۔ توثیق کرنے کے لیے فنگر پرنٹ سینسر کو ٹچ کریں۔"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"جاری فون کال"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"ہوائی جہاز وضع"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g> / <xliff:g id="STATE">%1$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"انٹرنیٹ خود کار طور پر منسلک نہیں ہوگا"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"کوئی کنکشن نہیں"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"کوئی دوسرا نیٹ ورک دستیاب نہیں ہے"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"کوئی نیٹ ورکس دستیاب نہیں ہیں"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"نیٹ ورکس کو دیکھنے کے لیے غیر مقفل کریں"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> درج ذیل ٹائل کو فوری ترتیبات میں شامل کرنا چاہتی ہے"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ٹائل شامل کریں"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ٹائل شامل نہ کریں"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index ee68d27..e91ec32 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Ekranga moslashtirish"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Ekran hajmida cho‘zish"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinshot"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock faolsizlantirildi"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"rasm yuborildi"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinshot saqlanmoqda…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinshot saqlanmoqda…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,22 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ochish uchun barmoq izidan foydalaning"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Haqiqiylikni tekshirish talab etiladi. Autentifikatsiya uchun barmoq izi skaneriga tegining."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Joriy telefon chaqiruvi"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Parvoz rejimi"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil internet"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Ulandi"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Internet avtomatik ravishda ulanmaydi"</string>
+    <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+    <skip />
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Internetga ulanmagansiz"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Boshqa tarmoqlar mavjud emas"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Hech qanday tarmoq mavjud emas"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Tarmoqlarni koʻrish uchun qulfdan chiqaring"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ilovasi Tezkor sozlamalarga quyidagi tugmani kiritmoqchi"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tugma kiritish"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tugma kiritilmasin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index c528165f..a52c999 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"T.phóng để lấp đầy m.hình"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Giãn ra để lấp đầy m.hình"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Tính năng Smart Lock đã tắt"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Đang lưu ảnh chụp màn hình..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Dùng vân tay để mở"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Bạn cần phải xác thực. Hãy chạm vào cảm biến vân tay để xác thực."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Đang gọi điện thoại"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Chế độ trên máy bay"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dữ liệu di động"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Đã kết nối"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"Sẽ không tự động kết nối Internet"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Dữ liệu di động sẽ không tự động kết nối"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Không có kết nối mạng"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Không có mạng nào khác"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Không có mạng"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Mở khóa để xem mạng"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> muốn thêm ô bên dưới vào trình đơn Cài đặt nhanh"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Thêm ô"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Không thêm ô"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4d7cdee..d9fadf6 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"缩放以填满屏幕"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"拉伸以填满屏幕"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在保存屏幕截图..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string>
@@ -184,6 +185,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>
@@ -1056,7 +1059,7 @@
     <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"收藏"</string>
     <string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"取消收藏"</string>
     <string name="accessibility_control_move" msgid="8980344493796647792">"移至位置 <xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="controls_favorite_default_title" msgid="967742178688938137">"控件"</string>
+    <string name="controls_favorite_default_title" msgid="967742178688938137">"控制"</string>
     <string name="controls_favorite_subtitle" msgid="6481675111056961083">"选择要从“快捷设置”菜单访问的控制项"</string>
     <string name="controls_favorite_rearrange" msgid="5616952398043063519">"按住并拖动即可重新排列控制器"</string>
     <string name="controls_favorite_removed" msgid="5276978408529217272">"已移除所有控制器"</string>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指纹即可打开"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要进行身份验证。请轻触指纹传感器以验证身份。"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"正在进行通话"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"飞行模式"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"不会自动连接到互联网"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"没有其他可用网络"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"没有可用网络"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"解锁即可查看网络"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"“<xliff:g id="APPNAME">%1$s</xliff:g>”希望将以下图块添加到“快捷设置”"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"添加图块"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加图块"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index ff4dddc..ee853ce 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"已傳送圖片"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕擷取畫面..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕擷取畫面..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。掂一下指紋感應器就可以驗證。"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"飛行模式"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"流動數據"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"不會自動連線至互聯網"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"不會自動連線至流動數據"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有連線"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網絡"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"沒有可用的網絡"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖即可查看網絡"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"「<xliff:g id="APPNAME">%1$s</xliff:g>」想在「快速設定」選單新增以下圖塊"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"新增圖塊"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不要新增圖塊"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 88b35a6..dccbcc4 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"傳送了一張圖片"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕截圖…"</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕截圖…"</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。輕觸指紋感應器即可進行驗證。"</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"飛航模式"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"行動數據"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"不會自動連上網際網路"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"系統將不會自動使用行動數據連線"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有網路連線"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網路"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"沒有可用的網路"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖螢幕即可查看網路"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"「<xliff:g id="APPNAME">%1$s</xliff:g>」想在快速設定選單新增以下設定方塊"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"新增設定方塊"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不要新增設定方塊"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 0e0e893..683890f 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -77,6 +77,7 @@
     <string name="compat_mode_on" msgid="4963711187149440884">"Sondeza ukugcwalisa isikrini"</string>
     <string name="compat_mode_off" msgid="7682459748279487945">"Nweba ukugcwalisa isikrini"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Isithombe-skrini"</string>
+    <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Ukhiye oSmathi ukhutshaziwe"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string>
     <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ilondoloz umfanekiso weskrini..."</string>
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string>
@@ -184,6 +185,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>
@@ -1159,18 +1162,21 @@
     <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Sebenzisa izigxivizo zeminwe ukuvula"</string>
     <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Ukufakazela ubuqiniso budingekile. Thinta inzwa yezigxivizo zeminwe ukuze uqinisekise."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ikholi yefoni eqhubekayo"</string>
-    <string name="airplane_mode" msgid="2536350001462130668">"Imodi yendiza"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Idatha yeselula"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Ixhunyiwe"</string>
-    <string name="mobile_data_off_summary" msgid="5621158216585822679">"I-inthanethi ngeke ixhumeke ngokuzenzakalelayo"</string>
+    <string name="mobile_data_off_summary" msgid="3663995422004150567">"Idatha yeselula ngeke ikwazi ukuxhuma ngokuzenzekelayo"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Alukho uxhumano"</string>
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Awekho amanye amanethiwekhi atholakalayo"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Awekho amanethiwekhi atholakalayo"</string>
     <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>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"Vula ukuze ubuke amanethiwekhi"</string>
     <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>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"I-<xliff:g id="APPNAME">%1$s</xliff:g> ifuna ukwengeza ithayela elilandelayo Kumasethingi Asheshayo"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Engeza ithayela"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ungafaki ithayela"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 3121ce3..db69924 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -77,6 +77,7 @@
         <attr name="numColumns" format="integer" />
         <attr name="verticalSpacing" format="dimension" />
         <attr name="horizontalSpacing" format="dimension" />
+        <attr name="fixedChildWidth" format="dimension" />
     </declare-styleable>
 
     <!-- Theme for icons in the status/nav bar (light/dark). background/fillColor is used for dual
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a4c1d94..2c19212 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -69,6 +69,9 @@
     <!-- Shadows under the clock, date and other keyguard text fields -->
     <color name="keyguard_shadow_color">#B2000000</color>
 
+    <!-- Color for the images in keyguard number pad buttons   -->
+    <color name="keyguard_keypad_image_color">@android:color/background_light</color>
+
     <!-- Color for rounded background for activated user in keyguard user switcher -->
     <color name="kg_user_switcher_activated_background_color">#26000000</color>
     <!-- Icon color for user avatars in keyguard user switcher -->
@@ -149,7 +152,6 @@
     <!-- Chosen so fill over background matches single tone -->
     <color name="dark_mode_qs_icon_color_dual_tone_fill">#99000000</color>
 
-    <color name="docked_divider_background">#ff000000</color>
     <color name="docked_divider_handle">#ffffff</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
     <color name="minimize_dock_shadow_start">#60000000</color>
@@ -187,7 +189,8 @@
     <!-- UDFPS colors -->
     <color name="udfps_enroll_icon">#000000</color>                         <!-- 100% black -->
     <color name="udfps_moving_target_fill">#cc4285f4</color>                <!-- 80% blue -->
-    <color name="udfps_enroll_progress">#ff669DF6</color>                   <!-- 100% blue -->
+    <color name="udfps_enroll_progress">#ff669DF6</color>                   <!-- blue 400 -->
+    <color name="udfps_enroll_progress_help">#ffEE675C</color>              <!-- red 400 -->
 
     <!-- Logout button -->
     <color name="logout_button_bg_color">#ccffffff</color>
@@ -284,13 +287,13 @@
 
     <!-- Internet Dialog -->
     <!-- Material next state on color-->
-    <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
+    <color name="settingslib_state_on_color">@color/settingslib_state_on</color>
     <!-- Material next state off color-->
-    <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
+    <color name="settingslib_state_off_color">@color/settingslib_state_off</color>
     <!-- Material next track on color-->
-    <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
+    <color name="settingslib_track_on_color">@color/settingslib_track_on</color>
     <!-- Material next track off color-->
-    <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
+    <color name="settingslib_track_off_color">@color/settingslib_track_off</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 721e1f3..fb90d63 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 -->
@@ -162,7 +162,7 @@
 
     <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
      card. -->
-    <integer name="keyguard_max_notification_count">3</integer>
+    <integer name="keyguard_max_notification_count">-1</integer>
 
     <!-- Defines the implementation of the velocity tracker to be used for the panel expansion. Can
          be 'platform' or 'noisy' (i.e. for noisy touch screens). -->
@@ -197,6 +197,11 @@
      low powered state yet. -->
     <bool name="doze_long_press_uses_prox">true</bool>
 
+    <!-- Doze: whether the brightness sensor uses the proximity sensor.
+     If both this parameter and doze_selectively_register_prox are true, registration for the
+     brightness sensor won't occur when the display state is ON. -->
+    <bool name="doze_brightness_uses_prox">true</bool>
+
     <!-- Doze: should notifications be used as a pulse signal? -->
     <bool name="doze_pulse_on_notifications">true</bool>
 
@@ -305,11 +310,6 @@
     <!-- Whether to show the full screen user switcher. -->
     <bool name="config_enableFullscreenUserSwitcher">false</bool>
 
-    <!-- Whether the multi-user switch on the keyguard opens QS user panel. If false, clicking the
-         user switch on the keyguard will replace the notifications and status area with the user
-         switcher. The multi-user switch is only shown if config_keyguardUserSwitcher=false. -->
-    <bool name="config_keyguard_user_switch_opens_qs_details">false</bool>
-
     <!-- SystemUIFactory component -->
     <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
 
@@ -700,4 +700,39 @@
          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>
+
+    <!-- Respect drawable/rounded_secondary.xml intrinsic size for multiple radius corner path
+         customization for secondary display-->
+    <bool name="config_roundedCornerMultipleRadiusSecondary">false</bool>
+
+    <!-- Whether the rounded corners are multiple radius for each display in a multi-display device.
+         {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+    <array name="config_roundedCornerMultipleRadiusArray">
+        <item>@bool/config_roundedCornerMultipleRadius</item>
+        <item>@bool/config_roundedCornerMultipleRadiusSecondary</item>
+    </array>
+
+    <!-- The rounded corner drawable for each display in a multi-display device.
+         {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+    <array name="config_roundedCornerDrawableArray">
+        <item>@drawable/rounded</item>
+        <item>@drawable/rounded_secondary</item>
+    </array>
+
+    <!-- The top rounded corner drawable for each display in a multi-display device.
+         {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+    <array name="config_roundedCornerTopDrawableArray">
+        <item>@drawable/rounded_corner_top</item>
+        <item>@drawable/rounded_corner_top_secondary</item>
+    </array>
+
+    <!-- The bottom rounded corner drawable for each display in a multi-display device.
+         {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+    <array name="config_roundedCornerBottomDrawableArray">
+        <item>@drawable/rounded_corner_bottom</item>
+        <item>@drawable/rounded_corner_bottom_secondary</item>
+    </array>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a12fd2b..6d792be 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -56,11 +56,6 @@
     <!-- The amount by which the arrow is shifted to avoid the finger-->
     <dimen name="navigation_edge_finger_offset">48dp</dimen>
 
-    <!-- Luminance threshold to determine black/white contrast for the navigation affordances -->
-    <item name="navigation_luminance_threshold" type="dimen" format="float">0.5</item>
-    <!-- Luminance change threshold that allows applying new value if difference was exceeded -->
-    <item name="navigation_luminance_change_threshold" type="dimen" format="float">0.05</item>
-
     <dimen name="floating_rotation_button_diameter">40dp</dimen>
     <dimen name="floating_rotation_button_min_margin">20dp</dimen>
     <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
@@ -333,11 +328,10 @@
     <dimen name="global_screenshot_x_scale">80dp</dimen>
     <dimen name="screenshot_bg_protection_height">242dp</dimen>
     <dimen name="screenshot_preview_elevation">4dp</dimen>
-    <dimen name="screenshot_offset_y">24dp</dimen>
+    <dimen name="screenshot_offset_y">8dp</dimen>
     <dimen name="screenshot_offset_x">16dp</dimen>
     <dimen name="screenshot_dismiss_button_tappable_size">48dp</dimen>
     <dimen name="screenshot_dismiss_button_margin">8dp</dimen>
-    <dimen name="screenshot_action_container_offset_y">16dp</dimen>
     <dimen name="screenshot_action_container_corner_radius">18dp</dimen>
     <dimen name="screenshot_action_container_padding_vertical">4dp</dimen>
     <dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
@@ -538,6 +532,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>
 
@@ -610,7 +607,7 @@
     <dimen name="qs_detail_item_primary_text_size">16sp</dimen>
     <dimen name="qs_detail_item_secondary_text_size">14sp</dimen>
     <dimen name="qs_detail_empty_text_size">14sp</dimen>
-    <dimen name="qs_detail_margin_top">28dp</dimen>
+    <dimen name="qs_detail_header_margin_top">28dp</dimen>
     <dimen name="qs_detail_back_margin_end">16dp</dimen>
     <dimen name="qs_detail_header_text_padding">16dp</dimen>
     <dimen name="qs_data_usage_text_size">14sp</dimen>
@@ -661,6 +658,8 @@
     <!-- Padding between subtitles and the following text in the QSFooter dialog -->
     <dimen name="qs_footer_dialog_subtitle_padding">20dp</dimen>
 
+    <dimen name="qs_detail_margin_top">@*android:dimen/quick_qs_offset_height</dimen>
+
     <dimen name="seek_bar_height">3dp</dimen>
     <dimen name="seek_bar_corner_radius">3dp</dimen>
 
@@ -918,6 +917,7 @@
 
     <dimen name="keyguard_affordance_fixed_height">48dp</dimen>
     <dimen name="keyguard_affordance_fixed_width">48dp</dimen>
+    <dimen name="keyguard_affordance_fixed_radius">24dp</dimen>
 
     <dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
     <dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
@@ -1135,6 +1135,7 @@
     <dimen name="global_actions_button_padding">38dp</dimen>
     <dimen name="global_actions_corner_radius">28dp</dimen>
     <dimen name="global_actions_lite_padding">24dp</dimen>
+    <dimen name="global_actions_info_margin">32dp</dimen>
 
     <!-- The maximum offset in either direction that elements are moved horizontally to prevent
          burn-in on AOD. -->
@@ -1146,7 +1147,7 @@
 
     <!-- The maximum offset in either direction that elements are moved vertically to prevent
          burn-in on AOD. -->
-    <dimen name="burn_in_prevention_offset_y_large_clock">42dp</dimen>
+    <dimen name="burn_in_prevention_offset_y_clock">42dp</dimen>
 
     <!-- Clock maximum font size (dp is intentional, to prevent any further scaling) -->
     <dimen name="large_clock_text_size">150dp</dimen>
@@ -1305,8 +1306,6 @@
     <dimen name="qs_media_action_margin">12dp</dimen>
     <dimen name="qs_seamless_height">24dp</dimen>
     <dimen name="qs_seamless_icon_size">12dp</dimen>
-    <dimen name="qs_seamless_fallback_icon_size">@dimen/qs_seamless_icon_size</dimen>
-    <dimen name="qs_seamless_fallback_margin">20dp</dimen>
     <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>
@@ -1337,6 +1336,7 @@
     <dimen name="magnifier_up_down_controls_height">40dp</dimen>
     <!-- The extra padding to show the whole outer border -->
     <dimen name="magnifier_drag_handle_padding">3dp</dimen>
+    <dimen name="magnification_max_frame_size">300dp</dimen>
 
     <!-- Home Controls -->
     <dimen name="controls_header_side_margin">4dp</dimen>
@@ -1468,6 +1468,10 @@
     <!-- Maximum overshoot for the pulse expansion -->
     <dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
 
+    <!-- Alpha in duration in ms for the auth ripple to become fully vislble. If set to 0,
+         it is immediately visible. -->
+    <integer name="auth_ripple_alpha_in_duration">100</integer>
+
     <dimen name="people_space_widget_radius">28dp</dimen>
     <dimen name="people_space_image_radius">20dp</dimen>
     <dimen name="people_space_messages_count_radius">12dp</dimen>
@@ -1595,35 +1599,48 @@
 
     <!-- Internet panel related dimensions -->
     <dimen name="internet_dialog_list_margin">12dp</dimen>
-    <dimen name="internet_dialog_list_max_height">614dp</dimen>
+    <dimen name="internet_dialog_list_max_height">646dp</dimen>
+    <dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen>
 
     <!-- Signal icon in internet dialog -->
     <dimen name="signal_strength_icon_size">24dp</dimen>
 
     <!-- Internet dialog related dimensions -->
     <dimen name="internet_dialog_corner_radius">24dp</dimen>
-
-    <!-- Size of internet dialog -->
+    <!-- End margin of network layout -->
+    <dimen name="internet_dialog_network_layout_margin">16dp</dimen>
+    <!-- Size of switch bar in internet dialog -->
     <dimen name="settingslib_switchbar_margin">16dp</dimen>
     <!-- Minimum width of switch -->
-    <dimen name="settingslib_min_switch_width">48dp</dimen>
+    <dimen name="settingslib_min_switch_width">52dp</dimen>
     <!-- Size of layout margin left -->
     <dimen name="settingslib_switchbar_padding_left">20dp</dimen>
     <!-- Size of layout margin right -->
     <dimen name="settingslib_switchbar_padding_right">20dp</dimen>
     <!-- Radius of switch bar -->
-    <dimen name="settingslib_switch_bar_radius">24dp</dimen>
+    <dimen name="settingslib_switch_bar_radius">35dp</dimen>
     <!-- Margin of switch thumb -->
     <dimen name="settingslib_switch_thumb_margin">4dp</dimen>
     <!-- Size of switch thumb -->
-    <dimen name="settingslib_switch_thumb_size">16dp</dimen>
+    <dimen name="settingslib_switch_thumb_size">20dp</dimen>
     <!-- Width of switch track -->
-    <dimen name="settingslib_switch_track_width">48dp</dimen>
+    <dimen name="settingslib_switch_track_width">52dp</dimen>
     <!-- Height of switch track -->
-    <dimen name="settingslib_switch_track_height">24dp</dimen>
+    <dimen name="settingslib_switch_track_height">28dp</dimen>
     <!-- Radius of switch track -->
-    <dimen name="settingslib_switch_track_radius">31dp</dimen>
+    <dimen name="settingslib_switch_track_radius">35dp</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>
+
+    <dimen name="qs_tile_service_request_dialog_width">304dp</dimen>
+    <dimen name="qs_tile_service_request_tile_width">192dp</dimen>
+    <dimen name="qs_tile_service_request_content_space">24dp</dimen>
+
+    <dimen name="qs_dialog_button_horizontal_padding">16dp</dimen>
+    <dimen name="qs_dialog_button_vertical_padding">8dp</dimen>
+    <!-- The button will be 48dp tall, but the background needs to be 36dp tall -->
+    <dimen name="qs_dialog_button_vertical_inset">6dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index c2b87a5..5ef9163 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -34,9 +34,14 @@
     <bool name="flag_lockscreen_animations">true</bool>
 
     <!-- The new swipe to unlock animation, which shows the app/launcher behind the keyguard during
-    the swipe. -->
+         the swipe. -->
     <bool name="flag_new_unlock_swipe_animation">true</bool>
 
+    <!-- Whether the multi-user icon on the lockscreen opens the QS user detail. If false, clicking
+         the multi-user icon will display a list of users directly on the lockscreen. The multi-user
+         icon is only shown if config_keyguardUserSwitcher=false in the frameworks config. -->
+    <bool name="flag_lockscreen_qs_user_detail_shortcut">false</bool>
+
     <!-- The shared-element transition between lockscreen smartspace and launcher smartspace. -->
     <bool name="flag_smartspace_shared_element_transition">false</bool>
 
@@ -51,4 +56,6 @@
     <bool name="flag_smartspace_deduping">true</bool>
 
     <bool name="flag_combined_status_bar_signal_icons">false</bool>
+
+    <bool name="flag_new_user_switcher">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a8812bf..5545437 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -211,6 +211,8 @@
 
     <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]-->
     <string name="global_action_screenshot">Screenshot</string>
+    <!-- Message shown in power menu when smart lock has been disabled [CHAR_LIMIT=NONE] -->
+    <string name="global_action_smart_lock_disabled">Smart Lock disabled</string>
 
     <!-- text to show in place of RemoteInput images when they cannot be shown.
          [CHAR LIMIT=50] -->
@@ -438,6 +440,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>
@@ -1004,7 +1008,7 @@
     <string name="sensor_privacy_start_use_mic_camera_dialog_content">This unblocks access for all apps and services allowed to use your camera or microphone.</string>
 
     <!-- Default name for the media device shown in the output switcher when the name is not available [CHAR LIMIT=30] -->
-    <string name="media_seamless_remote_device">Device</string>
+    <string name="media_seamless_other_device">Other device</string>
 
     <!-- QuickStep: Accessibility to toggle overview [CHAR LIMIT=40] -->
     <string name="quick_step_accessibility_toggle_overview">Toggle Overview</string>
@@ -2986,8 +2990,6 @@
     <!-- Content description for a chip in the status bar showing that the user is currently on a phone call. [CHAR LIMIT=NONE] -->
     <string name="ongoing_phone_call_content_description">Ongoing phone call</string>
 
-    <!-- Provider Model: Title of the airplane mode in the internet dialog. [CHAR LIMIT=50] -->
-    <string name="airplane_mode">Airplane mode</string>
     <!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] -->
     <string name="mobile_data_settings_title">Mobile data</string>
     <!-- Provider Model: Summary text separator for preferences including a short description
@@ -2998,7 +3000,7 @@
     <string name="mobile_data_connection_active">Connected</string>
     <!-- Provider Model:
      Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] -->
-    <string name="mobile_data_off_summary">Internet won\u0027t auto\u2011connect</string>
+    <string name="mobile_data_off_summary">Mobile data won\u0027t auto\u2011connect</string>
     <!-- Provider Model:
      Summary indicating that a active SIM and no network available [CHAR LIMIT=50] -->
     <string name="mobile_data_no_connection">No connection</string>
@@ -3012,10 +3014,20 @@
     <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 -->
     <string name="wifi_failed_connect_message">Failed to connect to network</string>
     <!-- Provider Model: Title to see all the networks [CHAR LIMIT=50] -->
     <string name="see_all_networks">See all</string>
+
+    <!-- Text for TileService request dialog. This is shown to the user that an app is requesting
+         user approval to add the shown tile to Quick Settings [CHAR LIMIT=NONE] -->
+    <string name="qs_tile_request_dialog_text"><xliff:g id="appName" example="Fake App">%1$s</xliff:g> wants to add the following tile to Quick Settings</string>
+    <!-- Text for TileService request dialog. Text for button for user to approve adding the tile [CHAR LIMIT=20] -->
+    <string name="qs_tile_request_dialog_add">Add tile</string>
+    <!-- Text for TileService request dialog. Text for button for user to reject adding the tile [CHAR LIMIT=20] -->
+    <string name="qs_tile_request_dialog_not_add">Do not add tile</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d254742..dc17afb 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -727,6 +727,16 @@
         <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
     </style>
 
+    <!-- TileService request dialog -->
+    <style name="TileRequestDialog" parent="Theme.SystemUI.QuickSettings.Dialog">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@drawable/qs_dialog_bg</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">true</item>
+        <item name="android:windowCloseOnTouchOutside">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+    </style>
+
     <!-- USB Contaminant dialog -->
     <style name ="USBContaminant" />
 
@@ -934,6 +944,39 @@
         <item name="actionDividerHeight">32dp</item>
     </style>
 
+    <style name="Theme.SystemUI.Dialog.QSDialog">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">true</item>
+        <item name="android:windowCloseOnTouchOutside">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:dialogCornerRadius">28dp</item>
+        <item name="android:buttonCornerRadius">28dp</item>
+        <item name="android:colorBackground">@color/prv_color_surface</item>
+    </style>
+
+    <style name="TextAppearance.QSDialog.Title" parent="Theme.SystemUI.Dialog.QSDialog">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">24sp</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:lineHeight">32sp</item>
+    </style>
+
+    <style name="Widget.QSDialog.Button" parent = "Theme.SystemUI.Dialog.QSDialog">
+        <item name="android:background">@drawable/qs_dialog_btn_filled</item>
+        <item name="android:textColor">@color/prv_text_color_on_accent</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:lineHeight">20sp</item>
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:stateListAnimator">@null</item>
+    </style>
+
+    <style name="Widget.QSDialog.Button.BorderButton">
+        <item name="android:background">@drawable/qs_dialog_btn_outline</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
     <style name="Theme.SystemUI.Dialog.Internet">
         <item name="android:windowBackground">@drawable/internet_dialog_background</item>
     </style>
diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml
index d6c6a60..c3510b6 100644
--- a/packages/SystemUI/res/xml/media_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_collapsed.xml
@@ -44,23 +44,6 @@
         />
 
     <Constraint
-        android:id="@+id/media_seamless_fallback"
-        android:layout_width="@dimen/qs_seamless_fallback_icon_size"
-        android:layout_height="@dimen/qs_seamless_fallback_icon_size"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_center_guideline_padding"
-        android:layout_marginEnd="@dimen/qs_seamless_fallback_margin"
-        android:alpha="0.5"
-        android:visibility="gone"
-        app:layout_constraintHorizontal_bias="1"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline"
-        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
-        app:layout_constraintEnd_toEndOf="parent"
-        />
-
-    <Constraint
         android:id="@+id/album_art"
         android:layout_width="@dimen/qs_media_album_size_small"
         android:layout_height="@dimen/qs_media_album_size_small"
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index 0e284e6..6b83aae 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -45,22 +45,6 @@
         android:layout_marginBottom="4dp" />
 
     <Constraint
-        android:id="@+id/media_seamless_fallback"
-        android:layout_width="@dimen/qs_seamless_fallback_icon_size"
-        android:layout_height="@dimen/qs_seamless_fallback_icon_size"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="16dp"
-        android:layout_marginStart="@dimen/qs_center_guideline_padding"
-        android:layout_marginEnd="@dimen/qs_seamless_fallback_margin"
-        android:alpha="0.5"
-        android:visibility="gone"
-        app:layout_constraintHorizontal_bias="1"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
-        app:layout_constraintEnd_toEndOf="parent"
-        />
-
-    <Constraint
         android:id="@+id/album_art"
         android:layout_width="@dimen/qs_media_album_size"
         android:layout_height="@dimen/qs_media_album_size"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
new file mode 100644
index 0000000..915e7f6
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.shared.animation
+
+import android.graphics.Point
+import android.util.MathUtils.lerp
+import android.view.Surface
+import android.view.View
+import android.view.WindowManager
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import java.lang.ref.WeakReference
+
+/**
+ * Creates an animation where all registered views are moved into their final location
+ * by moving from the center of the screen to the sides
+ */
+class UnfoldMoveFromCenterAnimator(
+    private val windowManager: WindowManager,
+    /**
+     * Allows to set custom translation applier
+     * Could be useful when a view could be translated from
+     * several sources and we want to set the translation
+     * using custom methods instead of [View.setTranslationX] or
+     * [View.setTranslationY]
+     */
+    var translationApplier: TranslationApplier = object : TranslationApplier {}
+) : UnfoldTransitionProgressProvider.TransitionProgressListener {
+
+    private val screenSize = Point()
+    private var isVerticalFold = false
+
+    private val animatedViews: MutableList<AnimatedView> = arrayListOf()
+    private val tmpArray = IntArray(2)
+
+    /**
+     * Updates display properties in order to calculate the initial position for the views
+     * Must be called before [registerViewForAnimation]
+     */
+    fun updateDisplayProperties() {
+        windowManager.defaultDisplay.getSize(screenSize)
+
+        // Simple implementation to get current fold orientation,
+        // this might not be correct on all devices
+        // TODO: use JetPack WindowManager library to get the fold orientation
+        isVerticalFold = windowManager.defaultDisplay.rotation == Surface.ROTATION_0 ||
+            windowManager.defaultDisplay.rotation == Surface.ROTATION_180
+    }
+
+    /**
+     * Registers a view to be animated, the view should be measured and layouted
+     * After finishing the animation it is necessary to clear
+     * the views using [clearRegisteredViews]
+     */
+    fun registerViewForAnimation(view: View) {
+        val animatedView = createAnimatedView(view)
+        animatedViews.add(animatedView)
+    }
+
+    /**
+     * Unregisters all registered views and resets their translation
+     */
+    fun clearRegisteredViews() {
+        onTransitionProgress(1f)
+        animatedViews.clear()
+    }
+
+    override fun onTransitionProgress(progress: Float) {
+        animatedViews.forEach {
+            it.view.get()?.let { view ->
+                translationApplier.apply(
+                    view = view,
+                    x = lerp(it.startTranslationX, it.finishTranslationX, progress),
+                    y = lerp(it.startTranslationY, it.finishTranslationY, progress)
+                )
+            }
+        }
+    }
+
+    private fun createAnimatedView(view: View): AnimatedView {
+        val viewLocation = tmpArray
+        view.getLocationOnScreen(viewLocation)
+
+        val viewX = viewLocation[0].toFloat()
+        val viewY = viewLocation[1].toFloat()
+
+        val viewCenterX = viewX + view.width / 2
+        val viewCenterY = viewY + view.height / 2
+
+        val translationXDiff: Float
+        val translationYDiff: Float
+
+        if (isVerticalFold) {
+            val distanceFromScreenCenterToViewCenter = screenSize.x / 2 - viewCenterX
+            translationXDiff = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
+            translationYDiff = 0f
+        } else {
+            val distanceFromScreenCenterToViewCenter = screenSize.y / 2 - viewCenterY
+            translationXDiff = 0f
+            translationYDiff = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
+        }
+
+        return AnimatedView(
+            view = WeakReference(view),
+            startTranslationX = view.translationX + translationXDiff,
+            startTranslationY = view.translationY + translationYDiff,
+            finishTranslationX = view.translationX,
+            finishTranslationY = view.translationY
+        )
+    }
+
+    /**
+     * Interface that allows to use custom logic to apply translation to view
+     */
+    interface TranslationApplier {
+        /**
+         * Called when we need to apply [x] and [y] translation to [view]
+         */
+        fun apply(view: View, x: Float, y: Float) {
+            view.translationX = x
+            view.translationY = y
+        }
+    }
+
+    private class AnimatedView(
+        val view: WeakReference<View>,
+        val startTranslationX: Float,
+        val startTranslationY: Float,
+        val finishTranslationX: Float,
+        val finishTranslationY: Float
+    )
+}
+
+private const val TRANSLATION_PERCENTAGE = 0.3f
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
rename to packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index c9a9399..9808374 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.navigationbar.gestural;
+package com.android.systemui.shared.navigationbar;
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import android.content.res.Resources;
+import android.annotation.TargetApi;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Handler;
 import android.view.CompositionSamplingListener;
 import android.view.SurfaceControl;
@@ -27,17 +28,22 @@
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
-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.
  */
+@TargetApi(Build.VERSION_CODES.Q)
 public class RegionSamplingHelper implements View.OnAttachStateChangeListener,
         View.OnLayoutChangeListener {
 
+    // Luminance threshold to determine black/white contrast for the navigation affordances.
+    // Passing the threshold of this luminance value will make the button black otherwise white
+    private static final float NAVIGATION_LUMINANCE_THRESHOLD = 0.5f;
+    // Luminance change threshold that allows applying new value if difference was exceeded
+    private static final float NAVIGATION_LUMINANCE_CHANGE_THRESHOLD = 0.05f;
+
     private final Handler mHandler = new Handler();
     private final View mSampledView;
 
@@ -62,13 +68,12 @@
     private boolean mWaitingOnDraw;
     private boolean mIsDestroyed;
 
-    // Passing the threshold of this luminance value will make the button black otherwise white
-    private final float mLuminanceThreshold;
-    private final float mLuminanceChangeThreshold;
     private boolean mFirstSamplingAfterStart;
     private boolean mWindowVisible;
     private boolean mWindowHasBlurs;
     private SurfaceControl mRegisteredStopLayer = null;
+    // A copy of mRegisteredStopLayer where we own the life cycle and can access from a bg thread.
+    private SurfaceControl mWrappedStopLayer = null;
     private ViewTreeObserver.OnDrawListener mUpdateOnDraw = new ViewTreeObserver.OnDrawListener() {
         @Override
         public void onDraw() {
@@ -100,9 +105,6 @@
         mSampledView.addOnAttachStateChangeListener(this);
         mSampledView.addOnLayoutChangeListener(this);
 
-        final Resources res = sampledView.getResources();
-        mLuminanceThreshold = res.getFloat(R.dimen.navigation_luminance_threshold);
-        mLuminanceChangeThreshold = res.getFloat(R.dimen.navigation_luminance_change_threshold);
         mCallback = samplingCallback;
     }
 
@@ -184,16 +186,21 @@
             }
             if (!mSamplingRequestBounds.equals(mRegisteredSamplingBounds)
                     || mRegisteredStopLayer != stopLayerControl) {
-                // We only want to reregister if something actually changed
+                // We only want to re-register if something actually changed
                 unregisterSamplingListener();
                 mSamplingListenerRegistered = true;
-                SurfaceControl registeredStopLayer = stopLayerControl;
+                SurfaceControl wrappedStopLayer = stopLayerControl == null
+                        ? null : new SurfaceControl(stopLayerControl, "regionSampling");
                 mBackgroundExecutor.execute(() -> {
+                    if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
+                        return;
+                    }
                     CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
-                            registeredStopLayer, mSamplingRequestBounds);
+                            wrappedStopLayer, mSamplingRequestBounds);
                 });
                 mRegisteredSamplingBounds.set(mSamplingRequestBounds);
-                mRegisteredStopLayer = registeredStopLayer;
+                mRegisteredStopLayer = stopLayerControl;
+                mWrappedStopLayer = wrappedStopLayer;
             }
             mFirstSamplingAfterStart = false;
         } else {
@@ -204,10 +211,14 @@
     private void unregisterSamplingListener() {
         if (mSamplingListenerRegistered) {
             mSamplingListenerRegistered = false;
+            SurfaceControl wrappedStopLayer = mWrappedStopLayer;
             mRegisteredStopLayer = null;
             mRegisteredSamplingBounds.setEmpty();
             mBackgroundExecutor.execute(() -> {
                 CompositionSamplingListener.unregister(mSamplingListener);
+                if (wrappedStopLayer != null && wrappedStopLayer.isValid()) {
+                    wrappedStopLayer.release();
+                }
             });
         }
     }
@@ -217,8 +228,10 @@
 
         // If the difference between the new luma and the current luma is larger than threshold
         // then apply the current luma, this is to prevent small changes causing colors to flicker
-        if (Math.abs(mCurrentMedianLuma - mLastMedianLuma) > mLuminanceChangeThreshold) {
-            mCallback.onRegionDarknessChanged(medianLuma < mLuminanceThreshold /* isRegionDark */);
+        if (Math.abs(mCurrentMedianLuma - mLastMedianLuma)
+                > NAVIGATION_LUMINANCE_CHANGE_THRESHOLD) {
+            mCallback.onRegionDarknessChanged(
+                    medianLuma < NAVIGATION_LUMINANCE_THRESHOLD /* isRegionDark */);
             mLastMedianLuma = medianLuma;
         }
     }
@@ -260,6 +273,7 @@
         pw.println("  mWindowHasBlurs: " + mWindowHasBlurs);
         pw.println("  mWaitingOnDraw: " + mWaitingOnDraw);
         pw.println("  mRegisteredStopLayer: " + mRegisteredStopLayer);
+        pw.println("  mWrappedStopLayer: " + mWrappedStopLayer);
         pw.println("  mIsDestroyed: " + mIsDestroyed);
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
index 42bc1d0..895b6cd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
@@ -15,31 +15,20 @@
 package com.android.systemui.shared.plugins;
 
 import android.content.Context;
-import android.os.Looper;
 
 /**
  * Provides necessary components for initializing {@link PluginManagerImpl}.
  */
 public interface PluginInitializer {
 
-    Looper getBgLooper();
-
     /**
-     * Called from the bg looper during initialization of {@link PluginManagerImpl}.
+     * Return a list of plugins that don't get disabled when an exception occurs.
      */
-    void onPluginManagerInit();
+    String[] getPrivilegedPlugins(Context context);
 
-    String[] getWhitelistedPlugins(Context context);
-
-    PluginEnabler getPluginEnabler(Context context);
 
     /**
-     * Called from {@link PluginManagerImpl#handleWtfs()}.
+     * Called from {@link PluginInstanceManager}.
      */
     void handleWtfs();
-
-    /**
-     * Returns if pluging manager should run in debug mode.
-     */
-    boolean isDebuggable();
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 2b35bcd..dcd3b3e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.shared.plugins;
 
+import android.app.LoadedApk;
 import android.app.Notification;
 import android.app.Notification.Action;
 import android.app.NotificationManager;
@@ -28,9 +29,8 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
+import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -42,9 +42,13 @@
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
 
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
 
 public class PluginInstanceManager<T extends Plugin> {
 
@@ -58,81 +62,70 @@
     private final String mAction;
     private final boolean mAllowMultiple;
     private final VersionInfo mVersion;
+    private final NotificationManager mNotificationManager;
+    private final PluginEnabler mPluginEnabler;
+    private final InstanceFactory<T> mInstanceFactory;
+    private final ArraySet<String> mPrivilegedPlugins = new ArraySet<>();
+    private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
 
     @VisibleForTesting
-    final MainHandler mMainHandler;
-    @VisibleForTesting
-    final PluginHandler mPluginHandler;
-    private final boolean isDebuggable;
+    private final ArrayList<PluginInfo<T>> mPlugins = new ArrayList<>();
+    private final boolean mIsDebuggable;
     private final PackageManager mPm;
-    private final PluginManagerImpl mManager;
-    private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
+    private final PluginInitializer mInitializer;
+    private final Executor mMainExecutor;
+    private final Executor mBgExecutor;
 
-    PluginInstanceManager(Context context, String action, PluginListener<T> listener,
-            boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
-        this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
-                manager, manager.isDebuggable(), manager.getWhitelistedPlugins());
-    }
+    private PluginManagerImpl.ClassLoaderFilter mParentClassLoader;
 
-    @VisibleForTesting
-    PluginInstanceManager(Context context, PackageManager pm, String action,
-            PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
-            PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
-        mMainHandler = new MainHandler(Looper.getMainLooper());
-        mPluginHandler = new PluginHandler(looper);
-        mManager = manager;
+    private PluginInstanceManager(Context context, PackageManager pm, String action,
+            PluginListener<T> listener, boolean allowMultiple, Executor mainExecutor,
+            Executor bgExecutor, VersionInfo version, boolean debuggable,
+            PluginInitializer initializer, NotificationManager notificationManager,
+            PluginEnabler pluginEnabler, List<String> privilegedPlugins,
+            InstanceFactory<T> instanceFactory) {
+        mInitializer = initializer;
+        mMainExecutor = mainExecutor;
+        mBgExecutor = bgExecutor;
         mContext = context;
         mPm = pm;
         mAction = action;
         mListener = listener;
         mAllowMultiple = allowMultiple;
         mVersion = version;
-        mWhitelistedPlugins.addAll(Arrays.asList(pluginWhitelist));
-        isDebuggable = debuggable;
-    }
-
-    public PluginInfo<T> getPlugin() {
-        if (Looper.myLooper() != Looper.getMainLooper()) {
-            throw new RuntimeException("Must be called from UI thread");
-        }
-        mPluginHandler.handleQueryPlugins(null /* All packages */);
-        if (mPluginHandler.mPlugins.size() > 0) {
-            mMainHandler.removeMessages(MainHandler.PLUGIN_CONNECTED);
-            PluginInfo<T> info = mPluginHandler.mPlugins.get(0);
-            PluginPrefs.setHasPlugins(mContext);
-            info.mPlugin.onCreate(mContext, info.mPluginContext);
-            return info;
-        }
-        return null;
+        mNotificationManager = notificationManager;
+        mPluginEnabler = pluginEnabler;
+        mInstanceFactory = instanceFactory;
+        mPrivilegedPlugins.addAll(privilegedPlugins);
+        mIsDebuggable = debuggable;
     }
 
     public void loadAll() {
         if (DEBUG) Log.d(TAG, "startListening");
-        mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
+        mBgExecutor.execute(this::queryAll);
     }
 
     public void destroy() {
         if (DEBUG) Log.d(TAG, "stopListening");
-        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);
-        for (PluginInfo plugin : plugins) {
-            mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,
-                    plugin.mPlugin).sendToTarget();
+        ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPlugins);
+        for (PluginInfo<T> pluginInfo : plugins) {
+            mMainExecutor.execute(() -> onPluginDisconnected(pluginInfo.mPlugin));
         }
     }
 
     public void onPackageRemoved(String pkg) {
-        mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
+        mBgExecutor.execute(() -> removePkg(pkg));
     }
 
     public void onPackageChange(String pkg) {
-        mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
-        mPluginHandler.obtainMessage(PluginHandler.QUERY_PKG, pkg).sendToTarget();
+        mBgExecutor.execute(() -> removePkg(pkg));
+        mBgExecutor.execute(() -> queryPkg(pkg));
     }
 
     public boolean checkAndDisable(String className) {
         boolean disableAny = false;
-        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);
-        for (PluginInfo info : plugins) {
+        ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPlugins);
+        for (PluginInfo<T> info : plugins) {
             if (className.startsWith(info.mPackage)) {
                 disableAny |= disable(info, PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH);
             }
@@ -141,7 +134,7 @@
     }
 
     public boolean disableAll() {
-        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);
+        ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPlugins);
         boolean disabledAny = false;
         for (int i = 0; i < plugins.size(); i++) {
             disabledAny |= disable(plugins.get(i), PluginEnabler.DISABLED_FROM_SYSTEM_CRASH);
@@ -149,8 +142,22 @@
         return disabledAny;
     }
 
-    private boolean isPluginWhitelisted(ComponentName pluginName) {
-        for (String componentNameOrPackage : mWhitelistedPlugins) {
+    private boolean isPluginPackagePrivileged(String packageName) {
+        for (String componentNameOrPackage : mPrivilegedPlugins) {
+            ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
+            if (componentName != null) {
+                if (componentName.getPackageName().equals(packageName)) {
+                    return true;
+                }
+            } else if (componentNameOrPackage.equals(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isPluginPrivileged(ComponentName pluginName) {
+        for (String componentNameOrPackage : mPrivilegedPlugins) {
             ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
             if (componentName == null) {
                 if (componentNameOrPackage.equals(pluginName.getPackageName())) {
@@ -165,7 +172,7 @@
         return false;
     }
 
-    private boolean disable(PluginInfo info, @PluginEnabler.DisableReason int reason) {
+    private boolean disable(PluginInfo<T> info, @PluginEnabler.DisableReason int reason) {
         // Live by the sword, die by the sword.
         // Misbehaving plugins get disabled and won't come back until uninstall/reinstall.
 
@@ -173,19 +180,19 @@
         // If a plugin is detected in the stack of a crash then this will be called for that
         // plugin, if the plugin causing a crash cannot be identified, they are all disabled
         // assuming one of them must be bad.
-        if (isPluginWhitelisted(pluginComponent)) {
+        if (isPluginPrivileged(pluginComponent)) {
             // Don't disable whitelisted plugins as they are a part of the OS.
             return false;
         }
         Log.w(TAG, "Disabling plugin " + pluginComponent.flattenToShortString());
-        mManager.getPluginEnabler().setDisabled(pluginComponent, reason);
+        mPluginEnabler.setDisabled(pluginComponent, reason);
 
         return true;
     }
 
-    public <T> boolean dependsOn(Plugin p, Class<T> cls) {
-        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);
-        for (PluginInfo info : plugins) {
+    <C> boolean dependsOn(Plugin p, Class<C> cls) {
+        ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPlugins);
+        for (PluginInfo<T> info : plugins) {
             if (info.mPlugin.getClass().getName().equals(p.getClass().getName())) {
                 return info.mVersion != null && info.mVersion.hasClass(cls);
             }
@@ -199,221 +206,259 @@
                 getClass().getSimpleName(), hashCode(), mAction);
     }
 
-    private class MainHandler extends Handler {
-        private static final int PLUGIN_CONNECTED = 1;
-        private static final int PLUGIN_DISCONNECTED = 2;
-
-        public MainHandler(Looper looper) {
-            super(looper);
+    private void onPluginConnected(PluginInfo<T> pluginInfo) {
+        if (DEBUG) Log.d(TAG, "onPluginConnected");
+        PluginPrefs.setHasPlugins(mContext);
+        mInitializer.handleWtfs();
+        if (!(pluginInfo.mPlugin instanceof PluginFragment)) {
+            // Only call onCreate for plugins that aren't fragments, as fragments
+            // will get the onCreate as part of the fragment lifecycle.
+            pluginInfo.mPlugin.onCreate(mContext, pluginInfo.mPluginContext);
         }
+        mListener.onPluginConnected(pluginInfo.mPlugin, pluginInfo.mPluginContext);
+    }
 
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case PLUGIN_CONNECTED:
-                    if (DEBUG) Log.d(TAG, "onPluginConnected");
-                    PluginPrefs.setHasPlugins(mContext);
-                    PluginInfo<T> info = (PluginInfo<T>) msg.obj;
-                    mManager.handleWtfs();
-                    if (!(msg.obj instanceof PluginFragment)) {
-                        // Only call onDestroy for plugins that aren't fragments, as fragments
-                        // will get the onCreate as part of the fragment lifecycle.
-                        info.mPlugin.onCreate(mContext, info.mPluginContext);
-                    }
-                    mListener.onPluginConnected(info.mPlugin, info.mPluginContext);
-                    break;
-                case PLUGIN_DISCONNECTED:
-                    if (DEBUG) Log.d(TAG, "onPluginDisconnected");
-                    mListener.onPluginDisconnected((T) msg.obj);
-                    if (!(msg.obj instanceof PluginFragment)) {
-                        // Only call onDestroy for plugins that aren't fragments, as fragments
-                        // will get the onDestroy as part of the fragment lifecycle.
-                        ((T) msg.obj).onDestroy();
-                    }
-                    break;
-                default:
-                    super.handleMessage(msg);
-                    break;
+    private void onPluginDisconnected(T plugin) {
+        if (DEBUG) Log.d(TAG, "onPluginDisconnected");
+        mListener.onPluginDisconnected(plugin);
+        if (!(plugin instanceof PluginFragment)) {
+            // Only call onDestroy for plugins that aren't fragments, as fragments
+            // will get the onDestroy as part of the fragment lifecycle.
+            plugin.onDestroy();
+        }
+    }
+
+    private void queryAll() {
+        if (DEBUG) Log.d(TAG, "queryAll " + mAction);
+        for (int i = mPlugins.size() - 1; i >= 0; i--) {
+            PluginInfo<T> pluginInfo = mPlugins.get(i);
+            mMainExecutor.execute(() -> onPluginDisconnected(pluginInfo.mPlugin));
+        }
+        mPlugins.clear();
+        handleQueryPlugins(null);
+    }
+
+    private void removePkg(String pkg) {
+        for (int i = mPlugins.size() - 1; i >= 0; i--) {
+            final PluginInfo<T> pluginInfo = mPlugins.get(i);
+            if (pluginInfo.mPackage.equals(pkg)) {
+                mMainExecutor.execute(() -> onPluginDisconnected(pluginInfo.mPlugin));
+                mPlugins.remove(i);
             }
         }
     }
 
-    private class PluginHandler extends Handler {
-        private static final int QUERY_ALL = 1;
-        private static final int QUERY_PKG = 2;
-        private static final int REMOVE_PKG = 3;
-
-        private final ArrayList<PluginInfo<T>> mPlugins = new ArrayList<>();
-
-        public PluginHandler(Looper looper) {
-            super(looper);
+    private void queryPkg(String pkg) {
+        if (DEBUG) Log.d(TAG, "queryPkg " + pkg + " " + mAction);
+        if (mAllowMultiple || (mPlugins.size() == 0)) {
+            handleQueryPlugins(pkg);
+        } else {
+            if (DEBUG) Log.d(TAG, "Too many of " + mAction);
         }
+    }
 
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case QUERY_ALL:
-                    if (DEBUG) Log.d(TAG, "queryAll " + mAction);
-                    for (int i = mPlugins.size() - 1; i >= 0; i--) {
-                        PluginInfo<T> pluginInfo = mPlugins.get(i);
-                        mMainHandler.obtainMessage(
-                                MainHandler.PLUGIN_DISCONNECTED, pluginInfo.mPlugin).sendToTarget();
-                    }
-                    mPlugins.clear();
-                    handleQueryPlugins(null);
-                    break;
-                case REMOVE_PKG:
-                    String pkg = (String) msg.obj;
-                    for (int i = mPlugins.size() - 1; i >= 0; i--) {
-                        final PluginInfo<T> plugin = mPlugins.get(i);
-                        if (plugin.mPackage.equals(pkg)) {
-                            mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,
-                                    plugin.mPlugin).sendToTarget();
-                            mPlugins.remove(i);
-                        }
-                    }
-                    break;
-                case QUERY_PKG:
-                    String p = (String) msg.obj;
-                    if (DEBUG) Log.d(TAG, "queryPkg " + p + " " + mAction);
-                    if (mAllowMultiple || (mPlugins.size() == 0)) {
-                        handleQueryPlugins(p);
-                    } else {
-                        if (DEBUG) Log.d(TAG, "Too many of " + mAction);
-                    }
-                    break;
-                default:
-                    super.handleMessage(msg);
-            }
+    private void handleQueryPlugins(String pkgName) {
+        // This isn't actually a service and shouldn't ever be started, but is
+        // a convenient PM based way to manage our plugins.
+        Intent intent = new Intent(mAction);
+        if (pkgName != null) {
+            intent.setPackage(pkgName);
         }
-
-        private void handleQueryPlugins(String pkgName) {
-            // This isn't actually a service and shouldn't ever be started, but is
-            // a convenient PM based way to manage our plugins.
-            Intent intent = new Intent(mAction);
-            if (pkgName != null) {
-                intent.setPackage(pkgName);
-            }
-            List<ResolveInfo> result = mPm.queryIntentServices(intent, 0);
-            if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");
-            if (result.size() > 1 && !mAllowMultiple) {
-                // TODO: Show warning.
-                Log.w(TAG, "Multiple plugins found for " + mAction);
-                if (DEBUG) {
-                    for (ResolveInfo info : result) {
-                        ComponentName name = new ComponentName(info.serviceInfo.packageName,
-                                info.serviceInfo.name);
-                        Log.w(TAG, "  " + name);
-                    }
+        List<ResolveInfo> result = mPm.queryIntentServices(intent, 0);
+        if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");
+        if (result.size() > 1 && !mAllowMultiple) {
+            // TODO: Show warning.
+            Log.w(TAG, "Multiple plugins found for " + mAction);
+            if (DEBUG) {
+                for (ResolveInfo info : result) {
+                    ComponentName name = new ComponentName(info.serviceInfo.packageName,
+                            info.serviceInfo.name);
+                    Log.w(TAG, "  " + name);
                 }
-                return;
             }
-            for (ResolveInfo info : result) {
-                ComponentName name = new ComponentName(info.serviceInfo.packageName,
-                        info.serviceInfo.name);
-                PluginInfo<T> t = handleLoadPlugin(name);
-                if (t == null) continue;
-
-                // add plugin before sending PLUGIN_CONNECTED message
-                mPlugins.add(t);
-                mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();
-            }
+            return;
         }
+        for (ResolveInfo info : result) {
+            ComponentName name = new ComponentName(info.serviceInfo.packageName,
+                    info.serviceInfo.name);
+            PluginInfo<T> pluginInfo = handleLoadPlugin(name);
+            if (pluginInfo == null) continue;
 
-        protected PluginInfo<T> handleLoadPlugin(ComponentName component) {
-            // This was already checked, but do it again here to make extra extra sure, we don't
-            // use these on production builds.
-            if (!isDebuggable && !isPluginWhitelisted(component)) {
-                // Never ever ever allow these on production builds, they are only for prototyping.
-                Log.w(TAG, "Plugin cannot be loaded on production build: " + component);
+            // add plugin before sending PLUGIN_CONNECTED message
+            mPlugins.add(pluginInfo);
+            mMainExecutor.execute(() -> onPluginConnected(pluginInfo));
+        }
+    }
+
+    protected PluginInfo<T> handleLoadPlugin(ComponentName component) {
+        // This was already checked, but do it again here to make extra extra sure, we don't
+        // use these on production builds.
+        if (!mIsDebuggable && !isPluginPrivileged(component)) {
+            // Never ever ever allow these on production builds, they are only for prototyping.
+            Log.w(TAG, "Plugin cannot be loaded on production build: " + component);
+            return null;
+        }
+        if (!mPluginEnabler.isEnabled(component)) {
+            if (DEBUG) Log.d(TAG, "Plugin is not enabled, aborting load: " + component);
+            return null;
+        }
+        String pkg = component.getPackageName();
+        String cls = component.getClassName();
+        try {
+            ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
+            // TODO: This probably isn't needed given that we don't have IGNORE_SECURITY on
+            if (mPm.checkPermission(PLUGIN_PERMISSION, pkg)
+                    != PackageManager.PERMISSION_GRANTED) {
+                Log.d(TAG, "Plugin doesn't have permission: " + pkg);
                 return null;
             }
-            if (!mManager.getPluginEnabler().isEnabled(component)) {
-                if (DEBUG) Log.d(TAG, "Plugin is not enabled, aborting load: " + component);
-                return null;
-            }
-            String pkg = component.getPackageName();
-            String cls = component.getClassName();
+            // Create our own ClassLoader so we can use our own code as the parent.
+            ClassLoader classLoader = getClassLoader(info);
+            Context pluginContext = new PluginContextWrapper(
+                    mContext.createApplicationContext(info, 0), classLoader);
+            Class<?> pluginClass = Class.forName(cls, true, classLoader);
+            // TODO: Only create the plugin before version check if we need it for
+            // legacy version check.
+            T plugin = mInstanceFactory.create(pluginClass);
             try {
-                ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
-                // TODO: This probably isn't needed given that we don't have IGNORE_SECURITY on
-                if (mPm.checkPermission(PLUGIN_PERMISSION, pkg)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    Log.d(TAG, "Plugin doesn't have permission: " + pkg);
-                    return null;
-                }
-                // Create our own ClassLoader so we can use our own code as the parent.
-                ClassLoader classLoader = mManager.getClassLoader(info);
-                Context pluginContext = new PluginContextWrapper(
-                        mContext.createApplicationContext(info, 0), classLoader);
-                Class<?> pluginClass = Class.forName(cls, true, classLoader);
-                // TODO: Only create the plugin before version check if we need it for
-                // legacy version check.
-                T plugin = (T) pluginClass.newInstance();
+                VersionInfo version = checkVersion(pluginClass, plugin, mVersion);
+                if (DEBUG) Log.d(TAG, "createPlugin");
+                return new PluginInfo<>(pkg, cls, plugin, pluginContext, version);
+            } catch (InvalidVersionException e) {
+                final int icon = Resources.getSystem().getIdentifier(
+                        "stat_sys_warning", "drawable", "android");
+                final int color = Resources.getSystem().getIdentifier(
+                        "system_notification_accent_color", "color", "android");
+                final Notification.Builder nb = new Notification.Builder(mContext,
+                        PluginManager.NOTIFICATION_CHANNEL_ID)
+                                .setStyle(new Notification.BigTextStyle())
+                                .setSmallIcon(icon)
+                                .setWhen(0)
+                                .setShowWhen(false)
+                                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                                .setColor(mContext.getColor(color));
+                String label = cls;
                 try {
-                    VersionInfo version = checkVersion(pluginClass, plugin, mVersion);
-                    if (DEBUG) Log.d(TAG, "createPlugin");
-                    return new PluginInfo(pkg, cls, plugin, pluginContext, version);
-                } catch (InvalidVersionException e) {
-                    final int icon = Resources.getSystem().getIdentifier(
-                            "stat_sys_warning", "drawable", "android");
-                    final int color = Resources.getSystem().getIdentifier(
-                            "system_notification_accent_color", "color", "android");
-                    final Notification.Builder nb = new Notification.Builder(mContext,
-                            PluginManager.NOTIFICATION_CHANNEL_ID)
-                                    .setStyle(new Notification.BigTextStyle())
-                                    .setSmallIcon(icon)
-                                    .setWhen(0)
-                                    .setShowWhen(false)
-                                    .setVisibility(Notification.VISIBILITY_PUBLIC)
-                                    .setColor(mContext.getColor(color));
-                    String label = cls;
-                    try {
-                        label = mPm.getServiceInfo(component, 0).loadLabel(mPm).toString();
-                    } catch (NameNotFoundException e2) {
-                    }
-                    if (!e.isTooNew()) {
-                        // Localization not required as this will never ever appear in a user build.
-                        nb.setContentTitle("Plugin \"" + label + "\" is too old")
-                                .setContentText("Contact plugin developer to get an updated"
-                                        + " version.\n" + e.getMessage());
-                    } else {
-                        // Localization not required as this will never ever appear in a user build.
-                        nb.setContentTitle("Plugin \"" + label + "\" is too new")
-                                .setContentText("Check to see if an OTA is available.\n"
-                                        + e.getMessage());
-                    }
-                    Intent i = new Intent(PluginManagerImpl.DISABLE_PLUGIN).setData(
-                            Uri.parse("package://" + component.flattenToString()));
-                    PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i,
-                            PendingIntent.FLAG_IMMUTABLE);
-                    nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
-                    mContext.getSystemService(NotificationManager.class)
-                            .notify(SystemMessage.NOTE_PLUGIN, nb.build());
-                    // TODO: Warn user.
-                    Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
-                            + ", expected " + mVersion);
-                    return null;
+                    label = mPm.getServiceInfo(component, 0).loadLabel(mPm).toString();
+                } catch (NameNotFoundException e2) {
                 }
-            } catch (Throwable e) {
-                Log.w(TAG, "Couldn't load plugin: " + pkg, e);
+                if (!e.isTooNew()) {
+                    // Localization not required as this will never ever appear in a user build.
+                    nb.setContentTitle("Plugin \"" + label + "\" is too old")
+                            .setContentText("Contact plugin developer to get an updated"
+                                    + " version.\n" + e.getMessage());
+                } else {
+                    // Localization not required as this will never ever appear in a user build.
+                    nb.setContentTitle("Plugin \"" + label + "\" is too new")
+                            .setContentText("Check to see if an OTA is available.\n"
+                                    + e.getMessage());
+                }
+                Intent i = new Intent(PluginManagerImpl.DISABLE_PLUGIN).setData(
+                        Uri.parse("package://" + component.flattenToString()));
+                PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i,
+                        PendingIntent.FLAG_IMMUTABLE);
+                nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
+                mNotificationManager.notify(SystemMessage.NOTE_PLUGIN, nb.build());
+                // TODO: Warn user.
+                Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
+                        + ", expected " + mVersion);
                 return null;
             }
+        } catch (Throwable e) {
+            Log.w(TAG, "Couldn't load plugin: " + pkg, e);
+            return null;
+        }
+    }
+
+    private VersionInfo checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
+            throws InvalidVersionException {
+        VersionInfo pv = new VersionInfo().addClass(pluginClass);
+        if (pv.hasVersionInfo()) {
+            version.checkVersion(pv);
+        } else {
+            int fallbackVersion = plugin.getVersion();
+            if (fallbackVersion != version.getDefaultVersion()) {
+                throw new InvalidVersionException("Invalid legacy version", false);
+            }
+            return null;
+        }
+        return pv;
+    }
+
+    /** Returns class loader specific for the given plugin. */
+    public ClassLoader getClassLoader(ApplicationInfo appInfo) {
+        if (!mIsDebuggable && !isPluginPackagePrivileged(appInfo.packageName)) {
+            Log.w(TAG, "Cannot get class loader for non-privileged plugin. Src:"
+                    + appInfo.sourceDir + ", pkg: " + appInfo.packageName);
+            return null;
+        }
+        if (mClassLoaders.containsKey(appInfo.packageName)) {
+            return mClassLoaders.get(appInfo.packageName);
         }
 
-        private VersionInfo checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
-                throws InvalidVersionException {
-            VersionInfo pv = new VersionInfo().addClass(pluginClass);
-            if (pv.hasVersionInfo()) {
-                version.checkVersion(pv);
-            } else {
-                int fallbackVersion = plugin.getVersion();
-                if (fallbackVersion != version.getDefaultVersion()) {
-                    throw new InvalidVersionException("Invalid legacy version", false);
-                }
-                return null;
-            }
-            return pv;
+        List<String> zipPaths = new ArrayList<>();
+        List<String> libPaths = new ArrayList<>();
+        LoadedApk.makePaths(null, true, appInfo, zipPaths, libPaths);
+        ClassLoader classLoader = new PathClassLoader(
+                TextUtils.join(File.pathSeparator, zipPaths),
+                TextUtils.join(File.pathSeparator, libPaths),
+                getParentClassLoader());
+        mClassLoaders.put(appInfo.packageName, classLoader);
+        return classLoader;
+    }
+
+    private ClassLoader getParentClassLoader() {
+        if (mParentClassLoader == null) {
+            // Lazily load this so it doesn't have any effect on devices without plugins.
+            mParentClassLoader = new PluginManagerImpl.ClassLoaderFilter(
+                    getClass().getClassLoader(), "com.android.systemui.plugin");
+        }
+        return mParentClassLoader;
+    }
+
+    /**
+     * Construct a {@link PluginInstanceManager}
+     */
+    public static class Factory {
+        private final Context mContext;
+        private final PackageManager mPackageManager;
+        private final Executor mMainExecutor;
+        private final Executor mBgExecutor;
+        private final PluginInitializer mInitializer;
+        private final NotificationManager mNotificationManager;
+        private final PluginEnabler mPluginEnabler;
+        private final List<String> mPrivilegedPlugins;
+        private InstanceFactory<?> mInstanceFactory;
+
+        public Factory(Context context, PackageManager packageManager,
+                Executor mainExecutor, Executor bgExecutor, PluginInitializer initializer,
+                NotificationManager notificationManager, PluginEnabler pluginEnabler,
+                List<String> privilegedPlugins) {
+            mContext = context;
+            mPackageManager = packageManager;
+            mMainExecutor = mainExecutor;
+            mBgExecutor = bgExecutor;
+            mInitializer = initializer;
+            mNotificationManager = notificationManager;
+            mPluginEnabler = pluginEnabler;
+            mPrivilegedPlugins = privilegedPlugins;
+
+            mInstanceFactory = new InstanceFactory<>();
+        }
+
+        @VisibleForTesting
+        <T extends Plugin> Factory setInstanceFactory(InstanceFactory<T> instanceFactory) {
+            mInstanceFactory = instanceFactory;
+            return this;
+        }
+
+        <T extends Plugin> PluginInstanceManager<T> create(
+                String action, PluginListener<T> listener, boolean allowMultiple,
+                VersionInfo version, boolean debuggable) {
+            return new PluginInstanceManager<T>(mContext, mPackageManager, action, listener,
+                    allowMultiple, mMainExecutor, mBgExecutor, version, debuggable,
+                    mInitializer, mNotificationManager, mPluginEnabler,
+                    mPrivilegedPlugins, (InstanceFactory<T>) mInstanceFactory);
         }
     }
 
@@ -443,10 +488,10 @@
         }
     }
 
-    static class PluginInfo<T> {
+    static class PluginInfo<T extends Plugin> {
         private final Context mPluginContext;
         private final VersionInfo mVersion;
-        private String mClass;
+        private final String mClass;
         T mPlugin;
         String mPackage;
 
@@ -459,4 +504,10 @@
             mVersion = info;
         }
     }
+
+    static class InstanceFactory<T extends Plugin> {
+        T create(Class cls) throws IllegalAccessException, InstantiationException {
+            return (T) cls.newInstance();
+        }
+    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java
index 3f907a8..d264bf2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java
@@ -27,10 +27,8 @@
     // must be one of the channels created in NotificationChannels.java
     String NOTIFICATION_CHANNEL_ID = "ALR";
 
-    String[] getWhitelistedPlugins();
-
-    <T extends Plugin> T getOneShotPlugin(Class<T> cls);
-    <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls);
+    /** Returns plugins that don't get disabled when an exceptoin occurs. */
+    String[] getPrivilegedPlugins();
 
     <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls);
     <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
@@ -38,7 +36,7 @@
     <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
             Class<?> cls);
     <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
-            Class cls, boolean allowMultiple);
+            Class<?> cls, boolean allowMultiple);
 
     void removePluginListener(PluginListener<?> listener);
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 2b4cdd6..ea7b0c3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -14,48 +14,31 @@
 
 package com.android.systemui.shared.plugins;
 
-import android.app.LoadedApk;
-import android.app.Notification;
-import android.app.Notification.Action;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.SystemProperties;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.widget.Toast;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
 
-import dalvik.system.PathClassLoader;
-
-import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.Thread.UncaughtExceptionHandler;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+
 /**
  * @see Plugin
  */
@@ -64,92 +47,42 @@
     private static final String TAG = PluginManagerImpl.class.getSimpleName();
     static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
 
-    private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
+    private final ArrayMap<PluginListener<?>, PluginInstanceManager<?>> mPluginMap
             = new ArrayMap<>();
     private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
-    private final ArraySet<String> mOneShotPackages = new ArraySet<>();
-    private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
+    private final ArraySet<String> mPrivilegedPlugins = new ArraySet<>();
     private final Context mContext;
-    private final PluginInstanceManagerFactory mFactory;
+    private final PluginInstanceManager.Factory mInstanceManagerFactory;
     private final boolean mIsDebuggable;
     private final PluginPrefs mPluginPrefs;
     private final PluginEnabler mPluginEnabler;
-    private final PluginInitializer mPluginInitializer;
-    private ClassLoaderFilter mParentClassLoader;
     private boolean mListening;
-    private boolean mHasOneShot;
-    private Looper mLooper;
 
-    public PluginManagerImpl(Context context, PluginInitializer initializer) {
-        this(context, new PluginInstanceManagerFactory(), initializer.isDebuggable(),
-                Thread.getUncaughtExceptionPreHandler(), initializer);
-    }
-
-    @VisibleForTesting
-    PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
-            UncaughtExceptionHandler defaultHandler, final PluginInitializer initializer) {
+    public PluginManagerImpl(Context context,
+            PluginInstanceManager.Factory instanceManagerFactory,
+            boolean debuggable,
+            Optional<UncaughtExceptionHandler> defaultHandlerOptional,
+            PluginEnabler pluginEnabler,
+            PluginPrefs pluginPrefs,
+            List<String> privilegedPlugins) {
         mContext = context;
-        mFactory = factory;
-        mLooper = initializer.getBgLooper();
+        mInstanceManagerFactory = instanceManagerFactory;
         mIsDebuggable = debuggable;
-        mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));
-        mPluginPrefs = new PluginPrefs(mContext);
-        mPluginEnabler = initializer.getPluginEnabler(mContext);
-        mPluginInitializer = initializer;
+        mPrivilegedPlugins.addAll(privilegedPlugins);
+        mPluginPrefs = pluginPrefs;
+        mPluginEnabler = pluginEnabler;
 
         PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
-                defaultHandler);
+                defaultHandlerOptional);
         Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
-
-        new Handler(mLooper).post(new Runnable() {
-            @Override
-            public void run() {
-                initializer.onPluginManagerInit();
-            }
-        });
     }
 
     public boolean isDebuggable() {
         return mIsDebuggable;
     }
 
-    public String[] getWhitelistedPlugins() {
-        return mWhitelistedPlugins.toArray(new String[0]);
-    }
-
-    public PluginEnabler getPluginEnabler() {
-        return mPluginEnabler;
-    }
-
-    // TODO(mankoff): This appears to be only called from tests. Remove?
-    public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
-        ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
-        if (info == null) {
-            throw new RuntimeException(cls + " doesn't provide an interface");
-        }
-        if (TextUtils.isEmpty(info.action())) {
-            throw new RuntimeException(cls + " doesn't provide an action");
-        }
-        return getOneShotPlugin(info.action(), cls);
-    }
-
-    public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
-        if (Looper.myLooper() != Looper.getMainLooper()) {
-            throw new RuntimeException("Must be called from UI thread");
-        }
-        // Passing null causes compiler to complain about incompatible (generic) types.
-        PluginListener<Plugin> dummy = null;
-        PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, dummy,
-                false, mLooper, cls, this);
-        mPluginPrefs.addAction(action);
-        PluginInfo<T> info = p.getPlugin();
-        if (info != null) {
-            mOneShotPackages.add(info.mPackage);
-            mHasOneShot = true;
-            startListening();
-            return info.mPlugin;
-        }
-        return null;
+    public String[] getPrivilegedPlugins() {
+        return mPrivilegedPlugins.toArray(new String[0]);
     }
 
     public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls) {
@@ -167,10 +100,10 @@
     }
 
     public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
-            Class cls, boolean allowMultiple) {
+            Class<?> cls, boolean allowMultiple) {
         mPluginPrefs.addAction(action);
-        PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
-                allowMultiple, mLooper, cls, this);
+        PluginInstanceManager<T> p = mInstanceManagerFactory.create(action, listener, allowMultiple,
+                new VersionInfo().addClass(cls), isDebuggable());
         p.loadAll();
         synchronized (this) {
             mPluginMap.put(listener, p);
@@ -208,8 +141,7 @@
     }
 
     private void stopListening() {
-        // Never stop listening if a one-shot is present.
-        if (!mListening || mHasOneShot) return;
+        if (!mListening) return;
         mListening = false;
         mContext.unregisterReceiver(this);
     }
@@ -218,7 +150,7 @@
     public void onReceive(Context context, Intent intent) {
         if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
             synchronized (this) {
-                for (PluginInstanceManager manager : mPluginMap.values()) {
+                for (PluginInstanceManager<?> manager : mPluginMap.values()) {
                     manager.loadAll();
                 }
             }
@@ -226,46 +158,17 @@
             Uri uri = intent.getData();
             ComponentName component = ComponentName.unflattenFromString(
                     uri.toString().substring(10));
-            if (isPluginWhitelisted(component)) {
-                // Don't disable whitelisted plugins as they are a part of the OS.
+            if (isPluginPrivileged(component)) {
+                // Don't disable privileged plugins as they are a part of the OS.
                 return;
             }
-            getPluginEnabler().setDisabled(component, PluginEnabler.DISABLED_INVALID_VERSION);
+            mPluginEnabler.setDisabled(component, PluginEnabler.DISABLED_INVALID_VERSION);
             mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(),
                     SystemMessage.NOTE_PLUGIN);
         } else {
             Uri data = intent.getData();
             String pkg = data.getEncodedSchemeSpecificPart();
             ComponentName componentName = ComponentName.unflattenFromString(pkg);
-            if (mOneShotPackages.contains(pkg)) {
-                int icon = Resources.getSystem().getIdentifier(
-                        "stat_sys_warning", "drawable", "android");
-                int color = Resources.getSystem().getIdentifier(
-                        "system_notification_accent_color", "color", "android");
-                String label = pkg;
-                try {
-                    PackageManager pm = mContext.getPackageManager();
-                    label = pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString();
-                } catch (NameNotFoundException e) {
-                }
-                // Localization not required as this will never ever appear in a user build.
-                final Notification.Builder nb =
-                        new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
-                                .setSmallIcon(icon)
-                                .setWhen(0)
-                                .setShowWhen(false)
-                                .setPriority(Notification.PRIORITY_MAX)
-                                .setVisibility(Notification.VISIBILITY_PUBLIC)
-                                .setColor(mContext.getColor(color))
-                                .setContentTitle("Plugin \"" + label + "\" has updated")
-                                .setContentText("Restart SysUI for changes to take effect.");
-                Intent i = new Intent("com.android.systemui.action.RESTART").setData(
-                            Uri.parse("package://" + pkg));
-                PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, PendingIntent.FLAG_MUTABLE_UNAUDITED);
-                nb.addAction(new Action.Builder(null, "Restart SysUI", pi).build());
-                mContext.getSystemService(NotificationManager.class)
-                        .notify(SystemMessage.NOTE_PLUGIN, nb.build());
-            }
             if (clearClassLoader(pkg)) {
                 if (Build.IS_ENG) {
                     Toast.makeText(mContext, "Reloading " + pkg, Toast.LENGTH_LONG).show();
@@ -276,22 +179,22 @@
             if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())
                     && componentName != null) {
                 @PluginEnabler.DisableReason int disableReason =
-                        getPluginEnabler().getDisableReason(componentName);
+                        mPluginEnabler.getDisableReason(componentName);
                 if (disableReason == PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH
                         || disableReason == PluginEnabler.DISABLED_FROM_SYSTEM_CRASH
                         || disableReason == PluginEnabler.DISABLED_INVALID_VERSION) {
                     Log.i(TAG, "Re-enabling previously disabled plugin that has been "
                             + "updated: " + componentName.flattenToShortString());
-                    getPluginEnabler().setEnabled(componentName);
+                    mPluginEnabler.setEnabled(componentName);
                 }
             }
             synchronized (this) {
                 if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                    for (PluginInstanceManager<?> manager : mPluginMap.values()) {
                         manager.onPackageChange(pkg);
                     }
                 } else {
-                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                    for (PluginInstanceManager<?> manager : mPluginMap.values()) {
                         manager.onPackageRemoved(pkg);
                     }
                 }
@@ -299,41 +202,10 @@
         }
     }
 
-    /** Returns class loader specific for the given plugin. */
-    public ClassLoader getClassLoader(ApplicationInfo appInfo) {
-        if (!mIsDebuggable && !isPluginPackageWhitelisted(appInfo.packageName)) {
-            Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
-                    + appInfo.sourceDir + ", pkg: " + appInfo.packageName);
-            return null;
-        }
-        if (mClassLoaders.containsKey(appInfo.packageName)) {
-            return mClassLoaders.get(appInfo.packageName);
-        }
-
-        List<String> zipPaths = new ArrayList<>();
-        List<String> libPaths = new ArrayList<>();
-        LoadedApk.makePaths(null, true, appInfo, zipPaths, libPaths);
-        ClassLoader classLoader = new PathClassLoader(
-                TextUtils.join(File.pathSeparator, zipPaths),
-                TextUtils.join(File.pathSeparator, libPaths),
-                getParentClassLoader());
-        mClassLoaders.put(appInfo.packageName, classLoader);
-        return classLoader;
-    }
-
     private boolean clearClassLoader(String pkg) {
         return mClassLoaders.remove(pkg) != null;
     }
 
-    ClassLoader getParentClassLoader() {
-        if (mParentClassLoader == null) {
-            // Lazily load this so it doesn't have any effect on devices without plugins.
-            mParentClassLoader = new ClassLoaderFilter(getClass().getClassLoader(),
-                    "com.android.systemui.plugin");
-        }
-        return mParentClassLoader;
-    }
-
     public <T> boolean dependsOn(Plugin p, Class<T> cls) {
         synchronized (this) {
             for (int i = 0; i < mPluginMap.size(); i++) {
@@ -345,46 +217,18 @@
         return false;
     }
 
-    public void handleWtfs() {
-        mPluginInitializer.handleWtfs();
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (this) {
             pw.println(String.format("  plugin map (%d):", mPluginMap.size()));
-            for (PluginListener listener : mPluginMap.keySet()) {
+            for (PluginListener<?> listener : mPluginMap.keySet()) {
                 pw.println(String.format("    %s -> %s",
                         listener, mPluginMap.get(listener)));
             }
         }
     }
 
-    @VisibleForTesting
-    public static class PluginInstanceManagerFactory {
-        public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
-                String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,
-                Class<?> cls, PluginManagerImpl manager) {
-            return new PluginInstanceManager(context, action, listener, allowMultiple, looper,
-                    new VersionInfo().addClass(cls), manager);
-        }
-    }
-
-    private boolean isPluginPackageWhitelisted(String packageName) {
-        for (String componentNameOrPackage : mWhitelistedPlugins) {
-            ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
-            if (componentName != null) {
-                if (componentName.getPackageName().equals(packageName)) {
-                    return true;
-                }
-            } else if (componentNameOrPackage.equals(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isPluginWhitelisted(ComponentName pluginName) {
-        for (String componentNameOrPackage : mWhitelistedPlugins) {
+    private boolean isPluginPrivileged(ComponentName pluginName) {
+        for (String componentNameOrPackage : mPrivilegedPlugins) {
             ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
             if (componentName != null) {
                 if (componentName.equals(pluginName)) {
@@ -399,7 +243,7 @@
 
     // This allows plugins to include any libraries or copied code they want by only including
     // classes from the plugin library.
-    private static class ClassLoaderFilter extends ClassLoader {
+    static class ClassLoaderFilter extends ClassLoader {
         private final String mPackage;
         private final ClassLoader mBase;
 
@@ -417,16 +261,20 @@
     }
 
     private class PluginExceptionHandler implements UncaughtExceptionHandler {
-        private final UncaughtExceptionHandler mHandler;
+        private final Optional<UncaughtExceptionHandler> mExceptionHandlerOptional;
 
-        private PluginExceptionHandler(UncaughtExceptionHandler handler) {
-            mHandler = handler;
+        private PluginExceptionHandler(
+                Optional<UncaughtExceptionHandler> exceptionHandlerOptional) {
+            mExceptionHandlerOptional = exceptionHandlerOptional;
         }
 
         @Override
         public void uncaughtException(Thread thread, Throwable throwable) {
             if (SystemProperties.getBoolean("plugin.debugging", false)) {
-                mHandler.uncaughtException(thread, throwable);
+                Throwable finalThrowable = throwable;
+                mExceptionHandlerOptional.ifPresent(
+                        handler -> handler.uncaughtException(thread, finalThrowable));
+
                 return;
             }
             // Search for and disable plugins that may have been involved in this crash.
@@ -436,7 +284,7 @@
                 // disable all the plugins, so we can be sure that SysUI is running as
                 // best as possible.
                 synchronized (this) {
-                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                    for (PluginInstanceManager<?> manager : mPluginMap.values()) {
                         disabledAny |= manager.disableAll();
                     }
                 }
@@ -446,7 +294,9 @@
             }
 
             // Run the normal exception handler so we can crash and cleanup our state.
-            mHandler.uncaughtException(thread, throwable);
+            Throwable finalThrowable = throwable;
+            mExceptionHandlerOptional.ifPresent(
+                    handler -> handler.uncaughtException(thread, finalThrowable));
         }
 
         private boolean checkStack(Throwable throwable) {
@@ -454,7 +304,7 @@
             boolean disabledAny = false;
             synchronized (this) {
                 for (StackTraceElement element : throwable.getStackTrace()) {
-                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                    for (PluginInstanceManager<?> manager : mPluginMap.values()) {
                         disabledAny |= manager.checkAndDisable(element.getClassName());
                     }
                 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index de9558e..8bd0f91 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -90,4 +90,9 @@
      * Sent when behavior changes. See WindowInsetsController#@Behavior
      */
     void onSystemBarAttributesChanged(int displayId, int behavior) = 20;
+
+    /**
+     * Sent when screen turned on and ready to use (blocker scrim is hidden)
+     */
+    void onScreenTurnedOn() = 21;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 4663a9a..196e6f3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -116,6 +116,8 @@
     public static final int SYSUI_STATE_IME_SWITCHER_SHOWING = 1 << 20;
     // Device dozing/AOD state
     public static final int SYSUI_STATE_DEVICE_DOZING = 1 << 21;
+    // The home feature is disabled (either by SUW/SysUI/device policy)
+    public static final int SYSUI_STATE_BACK_DISABLED = 1 << 22;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -139,7 +141,8 @@
             SYSUI_STATE_IME_SHOWING,
             SYSUI_STATE_MAGNIFICATION_OVERLAP,
             SYSUI_STATE_IME_SWITCHER_SHOWING,
-            SYSUI_STATE_DEVICE_DOZING
+            SYSUI_STATE_DEVICE_DOZING,
+            SYSUI_STATE_BACK_DISABLED
     })
     public @interface SystemUiStateFlags {}
 
@@ -170,6 +173,7 @@
         str.add((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0 ? "magnification_overlap" : "");
         str.add((flags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0 ? "ime_switcher_showing" : "");
         str.add((flags & SYSUI_STATE_DEVICE_DOZING) != 0 ? "device_dozing" : "");
+        str.add((flags & SYSUI_STATE_BACK_DISABLED) != 0 ? "back_disabled" : "");
         return str.toString();
     }
 
@@ -281,8 +285,8 @@
      * These values are expressed in pixels because they should not respect display or font
      * scaling, this means that we don't have to reload them on config changes.
      */
-    public static float getWindowCornerRadius(Resources resources) {
-        return ScreenDecorationsUtils.getWindowCornerRadius(resources);
+    public static float getWindowCornerRadius(Context context) {
+        return ScreenDecorationsUtils.getWindowCornerRadius(context);
     }
 
     /**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 025d7ef..7aee721 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -37,6 +37,7 @@
 import android.view.SurfaceControl;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 
 import java.util.ArrayList;
@@ -62,7 +63,8 @@
 
     /** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */
     public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner) {
-        return new RemoteTransitionCompat(wrapRemoteTransition(runner));
+        return new RemoteTransitionCompat(
+                new RemoteTransition(wrapRemoteTransition(runner)));
     }
 
     public RemoteTransitionCompat getRemoteTransition() {
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 23a365a..30db136 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
@@ -71,9 +71,13 @@
     public final boolean allowEnterPip;
     public final int rotationChange;
     public final int windowType;
+    public final WindowConfiguration windowConfiguration;
 
     private final SurfaceControl mStartLeash;
 
+    // Fields used only to unrap into RemoteAnimationTarget
+    private final Rect startBounds;
+
     public RemoteAnimationTargetCompat(RemoteAnimationTarget app) {
         taskId = app.taskId;
         mode = app.mode;
@@ -94,6 +98,8 @@
 
         mStartLeash = app.startLeash;
         windowType = app.windowType;
+        windowConfiguration = app.windowConfiguration;
+        startBounds = app.startBounds;
     }
 
     private static int newModeToLegacyMode(int newMode) {
@@ -109,6 +115,14 @@
         }
     }
 
+    public RemoteAnimationTarget unwrap() {
+        return new RemoteAnimationTarget(
+                taskId, mode, leash.getSurfaceControl(), isTranslucent, clipRect, contentInsets,
+                prefixOrderIndex, position, localBounds, screenSpaceBounds, windowConfiguration,
+                isNotInRecents, mStartLeash, startBounds, taskInfo, allowEnterPip, windowType
+        );
+    }
+
 
     /**
      * Almost a copy of Transitions#setupStartState.
@@ -216,10 +230,15 @@
             activityType = ACTIVITY_TYPE_UNDEFINED;
         }
         taskInfo = change.getTaskInfo();
-        allowEnterPip = false; /* always false in shell-transition case */
+        allowEnterPip = change.getAllowEnterPip();
         mStartLeash = null;
         rotationChange = change.getEndRotation() - change.getStartRotation();
         windowType = INVALID_WINDOW_TYPE;
+
+        windowConfiguration = change.getTaskInfo() != null
+            ? change.getTaskInfo().configuration.windowConfiguration
+            : new WindowConfiguration();
+        startBounds = change.getStartAbsBounds();
     }
 
     public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 2519284..9ec95a3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -41,6 +42,7 @@
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
 import android.window.PictureInPictureSurfaceTransaction;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 import android.window.TransitionInfo;
 import android.window.WindowContainerToken;
@@ -62,16 +64,16 @@
 public class RemoteTransitionCompat implements Parcelable {
     private static final String TAG = "RemoteTransitionCompat";
 
-    @NonNull final IRemoteTransition mTransition;
+    @NonNull final RemoteTransition mTransition;
     @Nullable TransitionFilter mFilter = null;
 
-    RemoteTransitionCompat(IRemoteTransition transition) {
+    RemoteTransitionCompat(RemoteTransition transition) {
         mTransition = transition;
     }
 
     public RemoteTransitionCompat(@NonNull RemoteTransitionRunner runner,
             @NonNull Executor executor) {
-        mTransition = new IRemoteTransition.Stub() {
+        IRemoteTransition remote = new IRemoteTransition.Stub() {
             @Override
             public void startAnimation(IBinder transition, TransitionInfo info,
                     SurfaceControl.Transaction t,
@@ -101,12 +103,13 @@
                         finishAdapter));
             }
         };
+        mTransition = new RemoteTransition(remote);
     }
 
     /** Constructor specifically for recents animation */
     public RemoteTransitionCompat(RecentsAnimationListener recents,
             RecentsAnimationControllerCompat controller) {
-        mTransition = new IRemoteTransition.Stub() {
+        IRemoteTransition remote = new IRemoteTransition.Stub() {
             final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap();
             IBinder mToken = null;
 
@@ -165,6 +168,7 @@
                 }
             }
         };
+        mTransition = new RemoteTransition(remote);
     }
 
     /** Adds a filter check that restricts this remote transition to home open transitions. */
@@ -172,6 +176,8 @@
         if (mFilter == null) {
             mFilter = new TransitionFilter();
         }
+        // No need to handle the transition that also dismisses keyguard.
+        mFilter.mNotFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
         mFilter.mRequirements =
                 new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(),
                         new TransitionFilter.Requirement()};
@@ -378,7 +384,7 @@
 
 
 
-    // Code below generated by codegen v1.0.21.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -390,8 +396,21 @@
     //   Settings > Editor > Code Style > Formatter Control
     //@formatter:off
 
+
     @DataClass.Generated.Member
-    public @NonNull IRemoteTransition getTransition() {
+    /* package-private */ RemoteTransitionCompat(
+            @NonNull RemoteTransition transition,
+            @Nullable TransitionFilter filter) {
+        this.mTransition = transition;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTransition);
+        this.mFilter = filter;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull RemoteTransition getTransition() {
         return mTransition;
     }
 
@@ -409,7 +428,7 @@
         byte flg = 0;
         if (mFilter != null) flg |= 0x2;
         dest.writeByte(flg);
-        dest.writeStrongInterface(mTransition);
+        dest.writeTypedObject(mTransition, flags);
         if (mFilter != null) dest.writeTypedObject(mFilter, flags);
     }
 
@@ -425,7 +444,7 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         byte flg = in.readByte();
-        IRemoteTransition transition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+        RemoteTransition transition = (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR);
         TransitionFilter filter = (flg & 0x2) == 0 ? null : (TransitionFilter) in.readTypedObject(TransitionFilter.CREATOR);
 
         this.mTransition = transition;
@@ -457,20 +476,20 @@
     @DataClass.Generated.Member
     public static class Builder {
 
-        private @NonNull IRemoteTransition mTransition;
+        private @NonNull RemoteTransition mTransition;
         private @Nullable TransitionFilter mFilter;
 
         private long mBuilderFieldsSet = 0L;
 
         public Builder(
-                @NonNull IRemoteTransition transition) {
+                @NonNull RemoteTransition transition) {
             mTransition = transition;
             com.android.internal.util.AnnotationValidations.validate(
                     NonNull.class, null, mTransition);
         }
 
         @DataClass.Generated.Member
-        public @NonNull Builder setTransition(@NonNull IRemoteTransition value) {
+        public @NonNull Builder setTransition(@NonNull RemoteTransition value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x1;
             mTransition = value;
@@ -493,8 +512,9 @@
             if ((mBuilderFieldsSet & 0x2) == 0) {
                 mFilter = null;
             }
-            RemoteTransitionCompat o = new RemoteTransitionCompat(mTransition);
-            o.mFilter = this.mFilter;
+            RemoteTransitionCompat o = new RemoteTransitionCompat(
+                    mTransition,
+                    mFilter);
             return o;
         }
 
@@ -507,10 +527,10 @@
     }
 
     @DataClass.Generated(
-            time = 1606862689344L,
-            codegenVersion = "1.0.21",
+            time = 1629321609807L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java",
-            inputSignatures = "final @android.annotation.NonNull com.android.systemui.shared.system.IRemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic  void addHomeOpenCheck()\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+            inputSignatures = "private static final  java.lang.String TAG\nfinal @android.annotation.NonNull android.window.RemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic  void addHomeOpenCheck(android.content.ComponentName)\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\nprivate  com.android.systemui.shared.system.RecentsAnimationControllerCompat mWrapped\nprivate  android.window.IRemoteTransitionFinishedCallback mFinishCB\nprivate  android.window.WindowContainerToken mPausingTask\nprivate  android.window.WindowContainerToken mPipTask\nprivate  android.window.TransitionInfo mInfo\nprivate  android.view.SurfaceControl mOpeningLeash\nprivate  android.util.ArrayMap<android.view.SurfaceControl,android.view.SurfaceControl> mLeashMap\nprivate  android.window.PictureInPictureSurfaceTransaction mPipTransaction\nprivate  android.os.IBinder mTransition\n  void setup(com.android.systemui.shared.system.RecentsAnimationControllerCompat,android.window.TransitionInfo,android.window.IRemoteTransitionFinishedCallback,android.window.WindowContainerToken,android.window.WindowContainerToken,android.util.ArrayMap<android.view.SurfaceControl,android.view.SurfaceControl>,android.os.IBinder)\n @android.annotation.SuppressLint boolean merge(android.window.TransitionInfo,android.view.SurfaceControl.Transaction,com.android.systemui.shared.system.RecentsAnimationListener)\npublic @java.lang.Override com.android.systemui.shared.recents.model.ThumbnailData screenshotTask(int)\npublic @java.lang.Override void setInputConsumerEnabled(boolean)\npublic @java.lang.Override void setAnimationTargetsBehindSystemBars(boolean)\npublic @java.lang.Override void hideCurrentInputMethod()\npublic @java.lang.Override void setFinishTaskTransaction(int,android.window.PictureInPictureSurfaceTransaction,android.view.SurfaceControl)\npublic @java.lang.Override @android.annotation.SuppressLint void finish(boolean,boolean)\npublic @java.lang.Override void setDeferCancelUntilNextTransition(boolean,boolean)\npublic @java.lang.Override void cleanupScreenshot()\npublic @java.lang.Override void setWillFinishToHome(boolean)\npublic @java.lang.Override boolean removeTask(int)\npublic @java.lang.Override void detachNavigationBarFromApp(boolean)\npublic @java.lang.Override void animateNavigationBarToApp(long)\nclass RecentsControllerWrap extends com.android.systemui.shared.system.RecentsAnimationControllerCompat implements []\n@com.android.internal.util.DataClass")
     @Deprecated
     private void __metadata() {}
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index b38270c..85d5de0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -27,10 +27,12 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.InsetsController;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.view.animation.Interpolator;
 
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -89,6 +91,9 @@
     public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT =
             InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
 
+    public static final int ANIMATION_DURATION_RESIZE = InsetsController.ANIMATION_DURATION_RESIZE;
+    public static final Interpolator RESIZE_INTERPOLATOR = InsetsController.RESIZE_INTERPOLATOR;
+
     private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
 
     public static WindowManagerWrapper getInstance() {
diff --git a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
similarity index 65%
rename from packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 7594f50..49cd279 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -15,21 +15,22 @@
  */
 @file:JvmName("UnfoldTransitionFactory")
 
-package com.android.unfold
+package com.android.systemui.unfold
 
 import android.content.Context
 import android.hardware.SensorManager
 import android.hardware.devicestate.DeviceStateManager
 import android.os.Handler
-import com.android.unfold.updates.screen.ScreenStatusProvider
-import com.android.unfold.config.ANIMATION_MODE_HINGE_ANGLE
-import com.android.unfold.config.ResourceUnfoldTransitionConfig
-import com.android.unfold.config.UnfoldTransitionConfig
-import com.android.unfold.progress.FixedTimingTransitionProgressProvider
-import com.android.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
-import com.android.unfold.updates.DeviceFoldStateProvider
-import com.android.unfold.updates.hinge.EmptyHingeAngleProvider
-import com.android.unfold.updates.hinge.RotationSensorHingeAngleProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.config.ANIMATION_MODE_HINGE_ANGLE
+import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
+import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
+import com.android.systemui.unfold.updates.DeviceFoldStateProvider
+import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
+import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
+import com.android.systemui.unfold.updates.hinge.RotationSensorHingeAngleProvider
 import java.lang.IllegalStateException
 import java.util.concurrent.Executor
 
@@ -50,7 +51,13 @@
 
     val hingeAngleProvider =
         if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
-            RotationSensorHingeAngleProvider(sensorManager)
+            // TODO: after removing temporary "config.mode" we should just
+            //       switch between fixed timing and hinge sensor based on this flag
+            if (config.isHingeAngleEnabled) {
+                HingeSensorAngleProvider(sensorManager)
+            } else {
+                RotationSensorHingeAngleProvider(sensorManager)
+            }
         } else {
             EmptyHingeAngleProvider()
         }
diff --git a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
similarity index 84%
rename from packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
index 2ddb49c..e17f43e 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold
+package com.android.systemui.unfold
 
 import android.annotation.FloatRange
-import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
 import com.android.systemui.statusbar.policy.CallbackController
 
 /**
@@ -31,8 +31,8 @@
     fun destroy()
 
     interface TransitionProgressListener {
-        fun onTransitionStarted()
-        fun onTransitionFinished()
-        fun onTransitionProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float)
+        fun onTransitionStarted() {}
+        fun onTransitionFinished() {}
+        fun onTransitionProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float) {}
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
similarity index 83%
rename from packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
index bde87a5..e7c6998a 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.config
+package com.android.systemui.unfold.config
 
 import android.content.Context
 import android.os.SystemProperties
@@ -25,6 +25,9 @@
     override val isEnabled: Boolean
         get() = readIsEnabled() && mode != ANIMATION_MODE_DISABLED
 
+    override val isHingeAngleEnabled: Boolean
+        get() = readIsHingeAngleEnabled()
+
     @AnimationMode
     override val mode: Int
         get() = SystemProperties.getInt(UNFOLD_TRANSITION_MODE_PROPERTY_NAME,
@@ -32,6 +35,9 @@
 
     private fun readIsEnabled(): Boolean = context.resources
         .getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
+
+    private fun readIsHingeAngleEnabled(): Boolean = context.resources
+        .getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle)
 }
 
 /**
diff --git a/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
similarity index 92%
rename from packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
index f000c69..a569757 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
@@ -13,12 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.config
+package com.android.systemui.unfold.config
 
 import android.annotation.IntDef
 
 interface UnfoldTransitionConfig {
     val isEnabled: Boolean
+    val isHingeAngleEnabled: Boolean
 
     @AnimationMode
     val mode: Int
diff --git a/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
similarity index 86%
rename from packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
index acfe073..732882e 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.progress
+package com.android.systemui.unfold.progress
 
 import android.animation.Animator
 import android.animation.ObjectAnimator
 import android.util.FloatProperty
-import com.android.unfold.UnfoldTransitionProgressProvider
-import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
-import com.android.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
-import com.android.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
-import com.android.unfold.updates.FoldStateProvider
-import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.systemui.unfold.updates.FoldStateProvider
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
 
 /**
  * Emits animation progress with fixed timing after unfolding
diff --git a/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
similarity index 78%
rename from packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index d9d037f..10e6c2b 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -13,27 +13,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.progress
+package com.android.systemui.unfold.progress
 
 import android.os.Handler
+import android.util.MathUtils.saturate
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringAnimation
 import androidx.dynamicanimation.animation.SpringForce
-import com.android.unfold.UnfoldTransitionProgressProvider
-import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
-import com.android.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
-import com.android.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
-import com.android.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
-import com.android.unfold.updates.FoldStateProvider
-import com.android.unfold.updates.FoldStateProvider.FoldUpdate
-import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
+import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.systemui.unfold.updates.FoldStateProvider
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
 
 /**
  * Maps fold updates to unfold transition progress using DynamicAnimation.
  *
  * TODO(b/193793338) Current limitations:
- *  - doesn't handle folding transition
  *  - doesn't handle postures
  */
 internal class PhysicsBasedUnfoldTransitionProgressProvider(
@@ -75,14 +76,20 @@
 
     override fun onHingeAngleUpdate(angle: Float) {
         if (!isTransitionRunning || isAnimatedCancelRunning) return
-        springAnimation.animateToFinalPosition(angle / 180f)
+        val progress = saturate(angle / FINAL_HINGE_ANGLE_POSITION)
+        springAnimation.animateToFinalPosition(progress)
     }
 
     override fun onFoldUpdate(@FoldUpdate update: Int) {
         when (update) {
             FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
-                onStartTransition()
                 startTransition(startValue = 0f)
+
+                // Stop the animation if the device has already opened by the time when
+                // the display is available as we won't receive the full open event anymore
+                if (foldStateProvider.isFullyOpened) {
+                    cancelTransition(endValue = 1f, animate = true)
+                }
             }
             FOLD_UPDATE_FINISH_FULL_OPEN -> {
                 cancelTransition(endValue = 1f, animate = true)
@@ -90,13 +97,16 @@
             FOLD_UPDATE_FINISH_CLOSED -> {
                 cancelTransition(endValue = 0f, animate = false)
             }
+            FOLD_UPDATE_START_CLOSING -> {
+                startTransition(startValue = 1f)
+            }
         }
     }
 
     private fun cancelTransition(endValue: Float, animate: Boolean) {
         handler.removeCallbacks(timeoutRunnable)
 
-        if (animate) {
+        if (isTransitionRunning && animate) {
             isAnimatedCancelRunning = true
             springAnimation.animateToFinalPosition(endValue)
         } else {
@@ -182,3 +192,4 @@
 private const val TRANSITION_TIMEOUT_MILLIS = 2000L
 private const val SPRING_STIFFNESS = 200.0f
 private const val MINIMAL_VISIBLE_CHANGE = 0.001f
+private const val FINAL_HINGE_ANGLE_POSITION = 165f
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
similarity index 78%
rename from packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 3a21b80..c37ab06 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -13,16 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.updates
+package com.android.systemui.unfold.updates
 
 import android.content.Context
 import android.hardware.devicestate.DeviceStateManager
 import androidx.core.util.Consumer
-import com.android.unfold.updates.screen.ScreenStatusProvider
-import com.android.unfold.updates.FoldStateProvider.FoldUpdate
-import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
-import com.android.unfold.updates.hinge.FULLY_OPEN_DEGREES
-import com.android.unfold.updates.hinge.HingeAngleProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES
+import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
 import java.util.concurrent.Executor
 
 internal class DeviceFoldStateProvider(
@@ -68,20 +68,29 @@
         outputListeners.remove(listener)
     }
 
+    override val isFullyOpened: Boolean
+        get() = !isFolded && lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN
+
     private fun onHingeAngle(angle: Float) {
         when (lastFoldUpdate) {
             FOLD_UPDATE_FINISH_FULL_OPEN -> {
-                if (FULLY_OPEN_DEGREES - angle > MOVEMENT_THRESHOLD_DEGREES) {
+                if (FULLY_OPEN_DEGREES - angle > START_CLOSING_THRESHOLD_DEGREES) {
                     lastFoldUpdate = FOLD_UPDATE_START_CLOSING
                     outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_CLOSING) }
                 }
             }
-            FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING -> {
+            FOLD_UPDATE_START_OPENING -> {
                 if (FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES) {
                     lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
                     outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
                 }
             }
+            FOLD_UPDATE_START_CLOSING -> {
+                if (FULLY_OPEN_DEGREES - angle < START_CLOSING_THRESHOLD_DEGREES) {
+                    lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
+                    outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
+                }
+            }
         }
 
         outputListeners.forEach { it.onHingeAngleUpdate(angle) }
@@ -120,5 +129,5 @@
     }
 }
 
-private const val MOVEMENT_THRESHOLD_DEGREES = 10f
-private const val FULLY_OPEN_THRESHOLD_DEGREES = 10f
\ No newline at end of file
+private const val START_CLOSING_THRESHOLD_DEGREES = 95f
+private const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
similarity index 92%
rename from packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index 2c3a6ec..11984b93 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.updates
+package com.android.systemui.unfold.updates
 
 import android.annotation.FloatRange
 import android.annotation.IntDef
-import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
 import com.android.systemui.statusbar.policy.CallbackController
 
 /**
@@ -28,6 +28,8 @@
     fun start()
     fun stop()
 
+    val isFullyOpened: Boolean
+
     interface FoldUpdatesListener {
         fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
         fun onFoldUpdate(@FoldUpdate update: Int)
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
similarity index 85%
rename from packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
index 905b086..9b58b1f 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt
@@ -1,4 +1,4 @@
-package com.android.unfold.updates.hinge
+package com.android.systemui.unfold.updates.hinge
 
 import androidx.core.util.Consumer
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
new file mode 100644
index 0000000..2520d35
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
@@ -0,0 +1,18 @@
+package com.android.systemui.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+import com.android.systemui.statusbar.policy.CallbackController
+
+/**
+ * Emits device hinge angle values (angle between two integral parts of the device).
+ * The hinge angle could be from 0 to 360 degrees inclusive.
+ * For foldable devices usually 0 corresponds to fully closed (folded) state and
+ * 180 degrees corresponds to fully open (flat) state
+ */
+internal interface HingeAngleProvider : CallbackController<Consumer<Float>> {
+    fun start()
+    fun stop()
+}
+
+const val FULLY_OPEN_DEGREES = 180f
+const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
new file mode 100644
index 0000000..a42ebef
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -0,0 +1,42 @@
+package com.android.systemui.unfold.updates.hinge
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import androidx.core.util.Consumer
+
+internal class HingeSensorAngleProvider(
+    private val sensorManager: SensorManager
+) : HingeAngleProvider {
+
+    private val sensorListener = HingeAngleSensorListener()
+    private val listeners: MutableList<Consumer<Float>> = arrayListOf()
+
+    override fun start() {
+        val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
+        sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+    }
+
+    override fun stop() {
+        sensorManager.unregisterListener(sensorListener)
+    }
+
+    override fun removeCallback(listener: Consumer<Float>) {
+        listeners.remove(listener)
+    }
+
+    override fun addCallback(listener: Consumer<Float>) {
+        listeners.add(listener)
+    }
+
+    private inner class HingeAngleSensorListener : SensorEventListener {
+
+        override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+        }
+
+        override fun onSensorChanged(event: SensorEvent) {
+            listeners.forEach { it.accept(event.values[0]) }
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
index 011582e..8b6eecf 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
@@ -1,4 +1,4 @@
-package com.android.unfold.updates.hinge
+package com.android.systemui.unfold.updates.hinge
 
 import android.hardware.Sensor
 import android.hardware.SensorEvent
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
similarity index 87%
rename from packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt
rename to packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
index a65e888..1eec803 100644
--- a/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.unfold.updates.screen
+package com.android.systemui.unfold.updates.screen
 
-import com.android.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
 import com.android.systemui.statusbar.policy.CallbackController
 
 interface ScreenStatusProvider : CallbackController<ScreenListener> {
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt
deleted file mode 100644
index 4196f60..0000000
--- a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.android.unfold.updates.hinge
-
-import androidx.core.util.Consumer
-import com.android.systemui.statusbar.policy.CallbackController
-
-internal interface HingeAngleProvider : CallbackController<Consumer<Float>> {
-    fun start()
-    fun stop()
-}
-
-const val FULLY_OPEN_DEGREES = 180f
-const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 27b6182..382e895 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,11 +93,14 @@
 
     private final ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
 
-    private ViewGroup mSmartspaceContainer;
+    // If set, will replace keyguard_status_area
+    private View mSmartspaceView;
 
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private SmartspaceTransitionController mSmartspaceTransitionController;
 
+    private boolean mOnlyClock = false;
+
     @Inject
     public KeyguardClockSwitchController(
             KeyguardClockSwitch keyguardClockSwitch,
@@ -130,6 +133,13 @@
     }
 
     /**
+     * Mostly used for alternate displays, limit the information shown
+     */
+    public void setOnlyClock(boolean onlyClock) {
+        mOnlyClock = onlyClock;
+    }
+
+    /**
      * Attach the controller to the view it relates to.
      */
     @Override
@@ -138,8 +148,6 @@
 
         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(
@@ -169,27 +177,47 @@
         }
         mColorExtractor.addOnColorsChangedListener(mColorsListener);
         mView.updateColors(getGradientColors());
+
+        if (mOnlyClock) {
+            View ksa = mView.findViewById(R.id.keyguard_status_area);
+            ksa.setVisibility(View.GONE);
+
+            View nic = mView.findViewById(
+                    R.id.left_aligned_notification_icon_container);
+            nic.setVisibility(View.GONE);
+            return;
+        }
         updateAodIcons();
 
-        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.
+        if (mSmartspaceController.isEnabled()) {
+            mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
 
             View ksa = mView.findViewById(R.id.keyguard_status_area);
-            // we show either keyguard_status_area or smartspace, so when smartspace can be visible,
-            // keyguard_status_area should be hidden
+            int ksaIndex = mView.indexOfChild(ksa);
             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);
-            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
-            lp.addRule(RelativeLayout.BELOW, mSmartspaceContainer.getId());
+            View nic = mView.findViewById(
+                    R.id.left_aligned_notification_icon_container);
+            lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
+            lp.addRule(RelativeLayout.BELOW, mSmartspaceView.getId());
             nic.setLayoutParams(lp);
-            mView.setSmartspaceView(mSmartspaceContainer);
-            mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceContainer);
+
+            mView.setSmartspaceView(mSmartspaceView);
+            mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
         }
     }
 
@@ -212,7 +240,10 @@
         // 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.
-        mSmartspaceContainer.removeAllViews();
+        if (mSmartspaceView != null) {
+            mView.removeView(mSmartspaceView);
+            mSmartspaceView = null;
+        }
     }
 
     /**
@@ -225,7 +256,7 @@
     }
 
     private void updateClockLayout() {
-        if (mSmartspaceController.isSmartspaceEnabled()) {
+        if (mSmartspaceController.isEnabled()) {
             RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
                     MATCH_PARENT);
             lp.topMargin = getContext().getResources().getDimensionPixelSize(
@@ -290,8 +321,8 @@
         PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y,
                 scale, props, animate);
 
-        if (mSmartspaceContainer != null) {
-            PropertyAnimator.setProperty(mSmartspaceContainer, AnimatableProperty.TRANSLATION_X,
+        if (mSmartspaceView != null) {
+            PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
                     x, props, animate);
 
             // If we're unlocking with the SmartSpace shared element transition, let the controller
@@ -309,8 +340,8 @@
     public void setChildrenAlphaExcludingSmartspace(float alpha) {
         final Set<View> excludedViews = new HashSet<>();
 
-        if (mSmartspaceContainer != null) {
-            excludedViews.add(mSmartspaceContainer);
+        if (mSmartspaceView != null) {
+            excludedViews.add(mSmartspaceView);
         }
 
         setChildrenAlphaExcluding(alpha, excludedViews);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 76a7473..cac90ea 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -332,6 +332,7 @@
                     .build(findViewById(R.id.clock))
                     .getKeyguardClockSwitchController();
 
+            mKeyguardClockSwitchController.setOnlyClock(true);
             mKeyguardClockSwitchController.init();
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
deleted file mode 100644
index 0785cc3..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.android.keyguard
-
-import android.annotation.CurrentTimeMillisLong
-
-/**
- * Data class for tracking information associated with [KeyguardUpdateMonitor.shouldListenForFace]
- * method calls.
- */
-data class KeyguardFaceListenModel(
-    @CurrentTimeMillisLong val timeMillis: Long,
-    val userId: Int,
-    val isListeningForFace: Boolean,
-    val isBouncer: Boolean,
-    val isAuthInterruptActive: Boolean,
-    val isOccludingAppRequestingFaceAuth: Boolean,
-    val isKeyguardAwake: Boolean,
-    val isListeningForFaceAssistant: Boolean,
-    val isSwitchingUser: Boolean,
-    val isFaceDisabled: Boolean,
-    val isBecauseCannotSkipBouncer: Boolean,
-    val isKeyguardGoingAway: Boolean,
-    val isBiometricSettingEnabledForUser: Boolean,
-    val isLockIconPressed: Boolean,
-    val isScanningAllowedByStrongAuth: Boolean,
-    val isPrimaryUser: Boolean,
-    val isSecureCameraLaunched: Boolean,
-    val isFaceAuthenticated: Boolean
-)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
new file mode 100644
index 0000000..e960e81
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -0,0 +1,68 @@
+package com.android.keyguard
+
+import android.annotation.CurrentTimeMillisLong
+
+/** Verbose logging for various keyguard listening states. */
+sealed class KeyguardListenModel {
+    /** Timestamp of the state change. */
+    abstract val timeMillis: Long
+    /** Current user. */
+    abstract val userId: Int
+    /** If keyguard is listening for the modality represented by this model. */
+    abstract val listening: Boolean
+}
+
+/**
+ * Verbose debug information associated with [KeyguardUpdateMonitor.shouldListenForFingerprint].
+ */
+data class KeyguardFingerprintListenModel(
+    @CurrentTimeMillisLong override val timeMillis: Long,
+    override val userId: Int,
+    override val listening: Boolean,
+    // keep sorted
+    val biometricEnabledForUser: Boolean,
+    val bouncer: Boolean,
+    val canSkipBouncer: Boolean,
+    val credentialAttempted: Boolean,
+    val deviceInteractive: Boolean,
+    val dreaming: Boolean,
+    val encryptedOrLockdown: Boolean,
+    val fingerprintDisabled: Boolean,
+    val fingerprintLockedOut: Boolean,
+    val goingToSleep: Boolean,
+    val keyguardGoingAway: Boolean,
+    val keyguardIsVisible: Boolean,
+    val keyguardOccluded: Boolean,
+    val occludingAppRequestingFp: Boolean,
+    val primaryUser: Boolean,
+    val shouldListenForFingerprintAssistant: Boolean,
+    val switchingUser: Boolean,
+    val udfps: Boolean,
+    val userDoesNotHaveTrust: Boolean,
+    val userNeedsStrongAuth: Boolean
+) : KeyguardListenModel()
+
+/**
+ * Verbose debug information associated with [KeyguardUpdateMonitor.shouldListenForFace].
+ */
+data class KeyguardFaceListenModel(
+    @CurrentTimeMillisLong override val timeMillis: Long,
+    override val userId: Int,
+    override val listening: Boolean,
+    // keep sorted
+    val authInterruptActive: Boolean,
+    val becauseCannotSkipBouncer: Boolean,
+    val biometricSettingEnabledForUser: Boolean,
+    val bouncer: Boolean,
+    val faceAuthenticated: Boolean,
+    val faceDisabled: Boolean,
+    val keyguardAwake: Boolean,
+    val keyguardGoingAway: Boolean,
+    val listeningForFaceAssistant: Boolean,
+    val lockIconPressed: Boolean,
+    val occludingAppRequestingFaceAuth: Boolean,
+    val primaryUser: Boolean,
+    val scanningAllowedByStrongAuth: Boolean,
+    val secureCameraLaunched: Boolean,
+    val switchingUser: Boolean
+) : KeyguardListenModel()
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
new file mode 100644
index 0000000..f13a59a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.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.keyguard
+
+import androidx.annotation.VisibleForTesting
+import java.io.PrintWriter
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+import kotlin.collections.ArrayDeque
+
+private val DEFAULT_FORMATTING = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US)
+
+/** Queue for verbose logging checks for the listening state. */
+class KeyguardListenQueue(
+    val sizePerModality: Int = 20
+) {
+    private val faceQueue = ArrayDeque<KeyguardFaceListenModel>()
+    private val fingerprintQueue = ArrayDeque<KeyguardFingerprintListenModel>()
+
+    @get:VisibleForTesting val models: List<KeyguardListenModel>
+        get() = faceQueue + fingerprintQueue
+
+    /** Push a [model] to the queue (will be logged until the queue exceeds [sizePerModality]). */
+    fun add(model: KeyguardListenModel) {
+        val queue = when (model) {
+            is KeyguardFaceListenModel -> faceQueue.apply { add(model) }
+            is KeyguardFingerprintListenModel -> fingerprintQueue.apply { add(model) }
+        }
+
+        if (queue.size > sizePerModality) {
+            queue.removeFirstOrNull()
+        }
+    }
+
+    /** Print verbose logs via the [writer]. */
+    @JvmOverloads
+    fun print(writer: PrintWriter, dateFormat: DateFormat = DEFAULT_FORMATTING) {
+        val stringify: (KeyguardListenModel) -> String = { model ->
+            "    ${dateFormat.format(Date(model.timeMillis))} $model"
+        }
+
+        writer.println("  Face listen results (last ${faceQueue.size} calls):")
+        for (model in faceQueue) {
+            writer.println(stringify(model))
+        }
+        writer.println("  Fingerprint listen results (last ${fingerprintQueue.size} calls):")
+        for (model in fingerprintQueue) {
+            writer.println(stringify(model))
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 840e8c8..26059068 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -317,7 +317,8 @@
             mRunningOneHandedAnimator = null;
         }
 
-        int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
+        int targetTranslation = mIsSecurityViewLeftAligned
+                ? 0 : (int) (getMeasuredWidth() - mSecurityViewFlipper.getWidth());
 
         if (animate) {
             mRunningOneHandedAnimator =
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index cb5c6c3..0df2d65 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -162,7 +162,9 @@
                     try {
                         Thread.sleep(5000);
                     } catch (InterruptedException ignored) { }
-                    Runtime.getRuntime().gc();
+                    System.gc();
+                    System.runFinalization();
+                    System.gc();
                 });
             } else {
                 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 8bf8e09..1804ad4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,6 +20,7 @@
 import android.util.Slog;
 
 import com.android.keyguard.KeyguardClockSwitch.ClockSize;
+import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
@@ -64,6 +65,7 @@
             KeyguardClockSwitchController keyguardClockSwitchController,
             KeyguardStateController keyguardStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
+            CommunalStateController communalStateController,
             ConfigurationController configurationController,
             DozeParameters dozeParameters,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -76,8 +78,9 @@
         mConfigurationController = configurationController;
         mDozeParameters = dozeParameters;
         mKeyguardStateController = keyguardStateController;
-        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
-                dozeParameters, unlockedScreenOffAnimationController, /* animateYPos= */ true);
+        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
+                keyguardStateController, dozeParameters, unlockedScreenOffAnimationController,
+                /* animateYPos= */ true, /* visibleOnCommunal= */ false);
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
         mSmartspaceTransitionController = smartspaceTransitionController;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ad196ef..92d1bc4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -118,15 +118,11 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.text.SimpleDateFormat;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -148,6 +144,7 @@
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     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_FINGERPRINT = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_SPEW = false;
     private static final int FINGERPRINT_LOCKOUT_RESET_DELAY_MS = 600;
 
@@ -347,13 +344,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;
@@ -419,9 +419,8 @@
     @VisibleForTesting
     SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
 
-    // Keep track of recent calls to shouldListenForFace() for debugging.
-    private static final int FACE_LISTEN_CALLS_QUEUE_SIZE = 20;
-    private ArrayDeque<KeyguardFaceListenModel> mFaceListenModels;
+    // Keep track of recent calls to shouldListenFor*() for debugging.
+    private final KeyguardListenQueue mListenModels = new KeyguardListenQueue();
 
     private static int sCurrentUser;
     private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
@@ -791,19 +790,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) {
@@ -905,6 +904,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();
@@ -983,10 +983,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);
@@ -2222,37 +2225,75 @@
 
     @VisibleForTesting
     protected boolean shouldListenForFingerprint(boolean isUdfps) {
-        final boolean userDoesNotHaveTrust = !getUserHasTrust(getCurrentUser());
+        final int user = getCurrentUser();
+        final boolean userDoesNotHaveTrust = !getUserHasTrust(user);
+        final boolean shouldListenForFingerprintAssistant = shouldListenForFingerprintAssistant();
         final boolean shouldListenKeyguardState =
                 mKeyguardIsVisible
                         || !mDeviceInteractive
                         || (mBouncer && !mKeyguardGoingAway)
                         || mGoingToSleep
-                        || shouldListenForFingerprintAssistant()
+                        || shouldListenForFingerprintAssistant
                         || (mKeyguardOccluded && mIsDreaming)
                         || (mKeyguardOccluded && userDoesNotHaveTrust
                             && (mOccludingAppRequestingFp || isUdfps));
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
+        final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
+        final boolean userCanSkipBouncer = getUserCanSkipBouncer(user);
+        final boolean fingerprintDisabledForUser = isFingerprintDisabled(user);
         final boolean shouldListenUserState =
                 !mSwitchingUser
-                        && !isFingerprintDisabled(getCurrentUser())
+                        && !fingerprintDisabledForUser
                         && (!mKeyguardGoingAway || !mDeviceInteractive)
                         && mIsPrimaryUser
-                        && mBiometricEnabledForUser.get(getCurrentUser());
+                        && biometricEnabledForUser;
 
         final boolean shouldListenBouncerState =
                 !(mFingerprintLockedOut && mBouncer && mCredentialAttempted);
 
+        final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user);
+        final boolean userNeedsStrongAuth = userNeedsStrongAuth();
         final boolean shouldListenUdfpsState = !isUdfps
-                || (!getUserCanSkipBouncer(getCurrentUser())
-                    && !isEncryptedOrLockdown(getCurrentUser())
-                    && !userNeedsStrongAuth()
+                || (!userCanSkipBouncer
+                    && !isEncryptedOrLockdownForUser
+                    && !userNeedsStrongAuth
                     && userDoesNotHaveTrust
                     && !mFingerprintLockedOut);
-        return shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState
-                && shouldListenUdfpsState;
+
+        final boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
+                && shouldListenBouncerState && shouldListenUdfpsState;
+
+        if (DEBUG_FINGERPRINT || DEBUG_SPEW) {
+            maybeLogListenerModelData(
+                    new KeyguardFingerprintListenModel(
+                        System.currentTimeMillis(),
+                        user,
+                        shouldListen,
+                        biometricEnabledForUser,
+                        mBouncer,
+                        userCanSkipBouncer,
+                        mCredentialAttempted,
+                        mDeviceInteractive,
+                        mIsDreaming,
+                        isEncryptedOrLockdownForUser,
+                        fingerprintDisabledForUser,
+                        mFingerprintLockedOut,
+                        mGoingToSleep,
+                        mKeyguardGoingAway,
+                        mKeyguardIsVisible,
+                        mKeyguardOccluded,
+                        mOccludingAppRequestingFp,
+                        mIsPrimaryUser,
+                        shouldListenForFingerprintAssistant,
+                        mSwitchingUser,
+                        isUdfps,
+                        userDoesNotHaveTrust,
+                        userNeedsStrongAuth));
+        }
+
+        return shouldListen;
     }
 
     /**
@@ -2276,12 +2317,12 @@
                 containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
                         || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
 
-        boolean canBypass = mKeyguardBypassController != null
+        final boolean canBypass = mKeyguardBypassController != null
                 && mKeyguardBypassController.canBypass();
         // There's no reason to ask the HAL for authentication when the user can dismiss the
         // bouncer, unless we're bypassing and need to auto-dismiss the lock screen even when
         // TrustAgents or biometrics are keeping the device unlocked.
-        boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
+        final boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
 
         // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
         // Lock-down mode shouldn't scan, since it is more explicit.
@@ -2289,69 +2330,72 @@
 
         // If the device supports face detection (without authentication), allow it to happen
         // if the device is in lockdown mode. Otherwise, prevent scanning.
-        boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty()
+        final boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty()
                 && mFaceSensorProperties.get(0).supportsFaceDetection;
         if (isLockDown && !supportsDetectOnly) {
             strongAuthAllowsScanning = false;
         }
 
         // If the face has recently been authenticated do not attempt to authenticate again.
-        boolean faceAuthenticated = getIsFaceAuthenticated();
+        final boolean faceAuthenticated = getIsFaceAuthenticated();
+        final boolean faceDisabledForUser = isFaceDisabled(user);
+        final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
+        final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         final boolean shouldListen =
                 (mBouncer || mAuthInterruptActive || mOccludingAppRequestingFace || awakeKeyguard
-                        || shouldListenForFaceAssistant())
-                && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
-                && !mKeyguardGoingAway && mBiometricEnabledForUser.get(user) && !mLockIconPressed
+                        || shouldListenForFaceAssistant)
+                && !mSwitchingUser && !faceDisabledForUser && becauseCannotSkipBouncer
+                && !mKeyguardGoingAway && biometricEnabledForUser && !mLockIconPressed
                 && strongAuthAllowsScanning && mIsPrimaryUser
                 && (!mSecureCameraLaunched || mOccludingAppRequestingFace)
                 && !faceAuthenticated;
 
         // Aggregate relevant fields for debug logging.
         if (DEBUG_FACE || DEBUG_SPEW) {
-            final KeyguardFaceListenModel model = new KeyguardFaceListenModel(
-                    System.currentTimeMillis(),
-                    user,
-                    shouldListen,
-                    mBouncer,
-                    mAuthInterruptActive,
-                    mOccludingAppRequestingFace,
-                    awakeKeyguard,
-                    shouldListenForFaceAssistant(),
-                    mSwitchingUser,
-                    isFaceDisabled(user),
-                    becauseCannotSkipBouncer,
-                    mKeyguardGoingAway,
-                    mBiometricEnabledForUser.get(user),
-                    mLockIconPressed,
-                    strongAuthAllowsScanning,
-                    mIsPrimaryUser,
-                    mSecureCameraLaunched,
-                    faceAuthenticated);
-            maybeLogFaceListenerModelData(model);
+            maybeLogListenerModelData(
+                    new KeyguardFaceListenModel(
+                        System.currentTimeMillis(),
+                        user,
+                        shouldListen,
+                        mAuthInterruptActive,
+                        becauseCannotSkipBouncer,
+                        biometricEnabledForUser,
+                        mBouncer,
+                        faceAuthenticated,
+                        faceDisabledForUser,
+                        awakeKeyguard,
+                        mKeyguardGoingAway,
+                        shouldListenForFaceAssistant,
+                        mLockIconPressed,
+                        mOccludingAppRequestingFace,
+                        mIsPrimaryUser,
+                        strongAuthAllowsScanning,
+                        mSecureCameraLaunched,
+                        mSwitchingUser));
         }
 
         return shouldListen;
     }
 
-    private void maybeLogFaceListenerModelData(KeyguardFaceListenModel model) {
+    private void maybeLogListenerModelData(KeyguardListenModel model) {
         // Too chatty, but very useful when debugging issues.
         if (DEBUG_SPEW) {
             Log.v(TAG, model.toString());
         }
 
         // Add model data to the historical buffer.
-        if (DEBUG_FACE && mFaceRunningState != BIOMETRIC_STATE_RUNNING
-                && model.isListeningForFace()) {
-            if (mFaceListenModels == null) {
-                mFaceListenModels = new ArrayDeque<>(FACE_LISTEN_CALLS_QUEUE_SIZE);
-            }
-            if (mFaceListenModels.size() >= FACE_LISTEN_CALLS_QUEUE_SIZE) {
-                mFaceListenModels.remove();
-            }
-            mFaceListenModels.add(model);
+        final boolean notYetRunning =
+                (DEBUG_FACE
+                    && model instanceof KeyguardFaceListenModel
+                    && mFaceRunningState != BIOMETRIC_STATE_RUNNING)
+                || (DEBUG_FINGERPRINT
+                    && model instanceof KeyguardFingerprintListenModel
+                    && mFingerprintRunningState != BIOMETRIC_STATE_RUNNING);
+        if (notYetRunning && model.getListening()) {
+            mListenModels.add(model);
         }
     }
 
@@ -2368,6 +2412,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;
@@ -2377,11 +2429,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)) {
@@ -2397,6 +2446,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;
@@ -2405,11 +2462,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
@@ -2461,9 +2515,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);
         }
@@ -2478,9 +2531,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);
         }
@@ -2842,6 +2894,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) {
@@ -3432,15 +3489,8 @@
             pw.println("    enabledByUser=" + mBiometricEnabledForUser.get(userId));
             pw.println("    mSecureCameraLaunched=" + mSecureCameraLaunched);
         }
-        if (mFaceListenModels != null && !mFaceListenModels.isEmpty()) {
-            final SimpleDateFormat dateFormat =
-                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
-            pw.println("  Face listen results (last " + FACE_LISTEN_CALLS_QUEUE_SIZE + " calls):");
-            for (final KeyguardFaceListenModel model : mFaceListenModels) {
-                final String time = dateFormat.format(new Date(model.getTimeMillis()));
-                pw.println("    " + time + " " + model.toString());
-            }
-        }
+        mListenModels.print(pw);
+
         if (mIsAutomotive) {
             pw.println("  Running on Automotive build");
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 28a54d5..23438a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -22,6 +22,7 @@
 import android.view.ViewPropertyAnimator;
 
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -38,24 +39,30 @@
 public class KeyguardVisibilityHelper {
 
     private View mView;
+    private final CommunalStateController mCommunalStateController;
     private final KeyguardStateController mKeyguardStateController;
     private final DozeParameters mDozeParameters;
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    private final boolean mVisibleOnCommunal;
     private boolean mAnimateYPos;
     private boolean mKeyguardViewVisibilityAnimating;
     private boolean mLastOccludedState = false;
     private final AnimationProperties mAnimationProperties = new AnimationProperties();
 
     public KeyguardVisibilityHelper(View view,
+            CommunalStateController communalStateController,
             KeyguardStateController keyguardStateController,
             DozeParameters dozeParameters,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            boolean animateYPos) {
+            boolean animateYPos,
+            boolean visibleOnCommunal) {
         mView = view;
+        mCommunalStateController = communalStateController;
         mKeyguardStateController = keyguardStateController;
         mDozeParameters = dozeParameters;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
         mAnimateYPos = animateYPos;
+        mVisibleOnCommunal = visibleOnCommunal;
     }
 
     public boolean isVisibilityAnimating() {
@@ -73,6 +80,14 @@
         mView.animate().cancel();
         boolean isOccluded = mKeyguardStateController.isOccluded();
         mKeyguardViewVisibilityAnimating = false;
+
+        // If the communal view is showing, hide immediately
+        if (!mVisibleOnCommunal && mCommunalStateController.getCommunalViewShowing()) {
+            mView.setVisibility(View.GONE);
+            mView.setAlpha(1f);
+            return;
+        }
+
         if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD
                 && statusBarState != KEYGUARD) || goingToFullShade) {
             mKeyguardViewVisibilityAnimating = true;
@@ -132,8 +147,7 @@
                         .alpha(1f)
                         .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
                         .start();
-            } else if (mUnlockedScreenOffAnimationController
-                        .isScreenOffLightRevealAnimationPlaying()) {
+            } else if (mUnlockedScreenOffAnimationController.shouldAnimateInKeyguard()) {
                 mKeyguardViewVisibilityAnimating = true;
 
                 // Ask the screen off animation controller to animate the keyguard visibility for us
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 622419a8..dd3bb89 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -22,12 +22,12 @@
 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 androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
@@ -80,7 +80,11 @@
         mLockIcon.setImageDrawable(drawable);
     }
 
-    void setCenterLocation(@NonNull PointF center, int radius) {
+    /**
+     * Set the location of the lock icon.
+     */
+    @VisibleForTesting
+    public void setCenterLocation(@NonNull PointF center, int radius) {
         mLockIconCenter = center;
         mRadius = radius;
 
@@ -91,13 +95,11 @@
                 mLockIconCenter.x + mRadius,
                 mLockIconCenter.y + mRadius);
 
-        setX(mSensorRect.left);
-        setY(mSensorRect.top);
-
-        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
-                (int) (mSensorRect.right - mSensorRect.left),
-                (int) (mSensorRect.bottom - mSensorRect.top));
-        lp.gravity = Gravity.CENTER;
+        final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        lp.width = (int) (mSensorRect.right - mSensorRect.left);
+        lp.height = (int) (mSensorRect.bottom - mSensorRect.top);
+        lp.topMargin = (int) mSensorRect.top;
+        lp.setMarginStart((int) mSensorRect.left);
         setLayoutParams(lp);
     }
 
@@ -114,5 +116,6 @@
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
         pw.println("Radius in pixels: " + mRadius);
+        pw.println("topLeft= (" + getX() + ", " + getY() + ")");
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 4317e25..2a4022c 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -46,6 +46,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.AuthRippleController;
 import com.android.systemui.biometrics.UdfpsController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
@@ -67,7 +68,8 @@
 /**
  * Controls when to show the LockIcon affordance (lock/unlocked icon or circle) on lock screen.
  *
- * This view will only be shown if the user has UDFPS or FaceAuth enrolled
+ * For devices with UDFPS, the lock icon will show at the sensor location. Else, the lock
+ * icon will show a set distance from the bottom of the device.
  */
 @StatusBarComponent.StatusBarScope
 public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
@@ -99,6 +101,7 @@
     @NonNull private CharSequence mUnlockedLabel;
     @NonNull private CharSequence mLockedLabel;
     @Nullable private final Vibrator mVibrator;
+    @Nullable private final AuthRippleController mAuthRippleController;
 
     private boolean mIsDozing;
     private boolean mIsBouncerShowing;
@@ -135,7 +138,8 @@
             @NonNull AccessibilityManager accessibilityManager,
             @NonNull ConfigurationController configurationController,
             @NonNull @Main DelayableExecutor executor,
-            @Nullable Vibrator vibrator
+            @Nullable Vibrator vibrator,
+            @Nullable AuthRippleController authRippleController
     ) {
         super(view);
         mStatusBarStateController = statusBarStateController;
@@ -148,6 +152,7 @@
         mConfigurationController = configurationController;
         mExecutor = executor;
         mVibrator = vibrator;
+        mAuthRippleController = authRippleController;
 
         final Context context = view.getContext();
         mUnlockIcon = mView.getContext().getResources().getDrawable(
@@ -168,15 +173,14 @@
 
     @Override
     protected void onInit() {
+        mAuthController.addCallback(mAuthControllerCallback);
+        mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+
         mView.setAccessibilityDelegate(mAccessibilityDelegate);
     }
 
     @Override
     protected void onViewAttached() {
-        // we check this here instead of onInit since the FingerprintManager + FaceManager may not
-        // have started up yet onInit
-        mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
-
         updateConfiguration();
         updateKeyguardShowing();
         mUserUnlockedWithBiometric = false;
@@ -497,8 +501,10 @@
                     if (!wasClickableOnDownEvent()) {
                         return;
                     }
+                    mDetectedLongPress = true;
 
-                    if (mVibrator != null) {
+                    if (onAffordanceClick() && mVibrator != null) {
+                        // only vibrate if the click went through and wasn't intercepted by falsing
                         mVibrator.vibrate(
                                 Process.myUid(),
                                 getContext().getOpPackageName(),
@@ -506,15 +512,21 @@
                                 "lockIcon-onLongPress",
                                 VIBRATION_SONIFICATION_ATTRIBUTES);
                     }
-                    mDetectedLongPress = true;
-                    onAffordanceClick();
                 }
 
                 public boolean onSingleTapUp(MotionEvent e) {
                     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;
                 }
@@ -523,15 +535,24 @@
                     return mDownDetected;
                 }
 
-                private void onAffordanceClick() {
+                /**
+                 * Whether we tried to launch the affordance.
+                 *
+                 * If falsing intercepts the click, returns false.
+                 */
+                private boolean onAffordanceClick() {
                     if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
-                        return;
+                        return false;
                     }
 
                     // pre-emptively set to true to hide view
                     mIsBouncerShowing = true;
+                    if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
+                        mAuthRippleController.showRipple(FINGERPRINT);
+                    }
                     updateVisibility();
                     mKeyguardViewController.showBouncer(/* scrim */ true);
+                    return true;
                 }
             });
 
@@ -569,4 +590,12 @@
     public void setAlpha(float alpha) {
         mView.setAlpha(alpha);
     }
+
+    private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
+        @Override
+        public void onAllAuthenticatorsRegistered() {
+            mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+            updateConfiguration();
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 99f9558..c659bf7 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -26,7 +26,7 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.settingslib.Utils;
+import com.android.systemui.R;
 
 /**
  * Similar to the {@link NumPadKey}, but displays an image.
@@ -92,8 +92,7 @@
     public void reloadColors() {
         if (mAnimator != null) mAnimator.reloadColors(getContext());
 
-        int textColor = Utils.getColorAttrDefaultColor(getContext(),
-                android.R.attr.colorBackground);
-        ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
+        int imageColor = getContext().getColor(R.color.keyguard_keypad_image_color);
+        ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
index 49a617e..153da4b 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
@@ -19,6 +19,7 @@
 import com.android.keyguard.KeyguardStatusViewController;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 
 import dagger.BindsInstance;
 import dagger.Subcomponent;
@@ -34,7 +35,10 @@
     /** Simple factory for {@link KeyguardStatusBarViewComponent}. */
     @Subcomponent.Factory
     interface Factory {
-        KeyguardStatusBarViewComponent build(@BindsInstance KeyguardStatusBarView view);
+        KeyguardStatusBarViewComponent build(
+                @BindsInstance KeyguardStatusBarView view,
+                @BindsInstance NotificationPanelViewController.NotificationPanelViewStateProvider
+                        notificationPanelViewStateProvider);
     }
 
     /** Builds a {@link KeyguardStatusViewController}. */
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 06fbe84..cc166c2 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -92,9 +92,11 @@
 
     @Override
     public void startActivity(Intent intent, boolean dismissShade,
-            @Nullable ActivityLaunchAnimator.Controller animationController) {
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            boolean showOverLockscreenWhenLocked) {
         mActualStarterOptionalLazy.get().ifPresent(
-                starter -> starter.startActivity(intent, dismissShade, animationController));
+                starter -> starter.startActivity(intent, dismissShade, animationController,
+                    showOverLockscreenWhenLocked));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 48c5e5e..1214ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -115,7 +115,6 @@
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.RotationLockController;
@@ -245,7 +244,6 @@
     @Inject Lazy<BluetoothController> mBluetoothController;
     @Inject Lazy<LocationController> mLocationController;
     @Inject Lazy<RotationLockController> mRotationLockController;
-    @Inject Lazy<NetworkController> mNetworkController;
     @Inject Lazy<ZenModeController> mZenModeController;
     @Inject Lazy<HotspotController> mHotspotController;
     @Inject Lazy<CastController> mCastController;
@@ -391,8 +389,6 @@
 
         mProviders.put(RotationLockController.class, mRotationLockController::get);
 
-        mProviders.put(NetworkController.class, mNetworkController::get);
-
         mProviders.put(ZenModeController.class, mZenModeController::get);
 
         mProviders.put(HotspotController.class, mHotspotController::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index f653088..76ea8f3 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -42,6 +42,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
@@ -59,6 +60,7 @@
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.util.DisplayMetrics;
+import android.util.DisplayUtils;
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayCutout;
@@ -66,6 +68,7 @@
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.RoundedCorners;
 import android.view.Surface;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
@@ -159,6 +162,10 @@
     private boolean mIsRoundedCornerMultipleRadius;
     private int mStatusBarHeightPortrait;
     private int mStatusBarHeightLandscape;
+    private Drawable mRoundedCornerDrawable;
+    private Drawable mRoundedCornerDrawableTop;
+    private Drawable mRoundedCornerDrawableBottom;
+    private String mDisplayUniqueId;
 
     private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
             new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -244,10 +251,11 @@
 
     private void startOnScreenDecorationsThread() {
         mRotation = mContext.getDisplay().getRotation();
+        mDisplayUniqueId = mContext.getDisplay().getUniqueId();
+        mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
-        mIsRoundedCornerMultipleRadius = mContext.getResources().getBoolean(
-                R.bool.config_roundedCornerMultipleRadius);
+        updateRoundedCornerDrawable();
         updateRoundedCornerRadii();
         setupDecorations();
         setupCameraListener();
@@ -287,6 +295,14 @@
                         }
                     }
                 }
+                final String newUniqueId = mContext.getDisplay().getUniqueId();
+                if ((newUniqueId != null && !newUniqueId.equals(mDisplayUniqueId))
+                        || (mDisplayUniqueId != null && !mDisplayUniqueId.equals(newUniqueId))) {
+                    mDisplayUniqueId = newUniqueId;
+                    mIsRoundedCornerMultipleRadius =
+                            isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+                    updateRoundedCornerDrawable();
+                }
                 updateOrientation();
             }
         };
@@ -474,6 +490,7 @@
         updateRoundedCornerView(pos, R.id.left);
         updateRoundedCornerView(pos, R.id.right);
         updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
+        updateRoundedCornerImageView();
 
         // update cutout view rotation
         if (mCutoutViews != null && mCutoutViews[pos] != null) {
@@ -677,12 +694,12 @@
         // upgrading all of the configs to contain (width, height) pairs. Instead assume that a
         // device configured using the single integer config value is okay with drawing the corners
         // as a square
-        final int newRoundedDefault = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.rounded_corner_radius);
-        final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.rounded_corner_radius_top);
-        final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom);
+        final int newRoundedDefault = RoundedCorners.getRoundedCornerRadius(
+                mContext.getResources(), mDisplayUniqueId);
+        final int newRoundedDefaultTop = RoundedCorners.getRoundedCornerTopRadius(
+                mContext.getResources(), mDisplayUniqueId);
+        final int newRoundedDefaultBottom = RoundedCorners.getRoundedCornerBottomRadius(
+                mContext.getResources(), mDisplayUniqueId);
 
         final boolean changed = mRoundedDefault.x != newRoundedDefault
                         || mRoundedDefaultTop.x != newRoundedDefaultTop
@@ -692,12 +709,12 @@
             // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
             // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
             if (mIsRoundedCornerMultipleRadius) {
-                Drawable d =  mContext.getDrawable(R.drawable.rounded);
-                mRoundedDefault.set(d.getIntrinsicWidth(), d.getIntrinsicHeight());
-                d =  mContext.getDrawable(R.drawable.rounded_corner_top);
-                mRoundedDefaultTop.set(d.getIntrinsicWidth(), d.getIntrinsicHeight());
-                d =  mContext.getDrawable(R.drawable.rounded_corner_bottom);
-                mRoundedDefaultBottom.set(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+                mRoundedDefault.set(mRoundedCornerDrawable.getIntrinsicWidth(),
+                        mRoundedCornerDrawable.getIntrinsicHeight());
+                mRoundedDefaultTop.set(mRoundedCornerDrawableTop.getIntrinsicWidth(),
+                        mRoundedCornerDrawableTop.getIntrinsicHeight());
+                mRoundedDefaultBottom.set(mRoundedCornerDrawableBottom.getIntrinsicWidth(),
+                        mRoundedCornerDrawableBottom.getIntrinsicHeight());
             } else {
                 mRoundedDefault.set(newRoundedDefault, newRoundedDefault);
                 mRoundedDefaultTop.set(newRoundedDefaultTop, newRoundedDefaultTop);
@@ -707,6 +724,89 @@
         }
     }
 
+    /**
+     * Gets whether the rounded corners are multiple radii for current display.
+     *
+     * Loads the default config {@link R.bool#config_roundedCornerMultipleRadius} if
+     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+     */
+    private static boolean isRoundedCornerMultipleRadius(Context context, String displayUniqueId) {
+        final Resources res = context.getResources();
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(
+                R.array.config_roundedCornerMultipleRadiusArray);
+        boolean isMultipleRadius;
+        if (index >= 0 && index < array.length()) {
+            isMultipleRadius = array.getBoolean(index, false);
+        } else {
+            isMultipleRadius = res.getBoolean(R.bool.config_roundedCornerMultipleRadius);
+        }
+        array.recycle();
+        return isMultipleRadius;
+    }
+
+    /**
+     * Gets the rounded corner drawable for current display.
+     *
+     * Loads the default config {@link R.drawable#rounded} if
+     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+     */
+    private static Drawable getRoundedCornerDrawable(Context context, String displayUniqueId) {
+        final Resources res = context.getResources();
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerDrawableArray);
+        Drawable drawable;
+        if (index >= 0 && index < array.length()) {
+            drawable = array.getDrawable(index);
+        } else {
+            drawable = context.getDrawable(R.drawable.rounded);
+        }
+        array.recycle();
+        return drawable;
+    }
+
+    /**
+     * Gets the rounded corner top drawable for current display.
+     *
+     * Loads the default config {@link R.drawable#rounded_corner_top} if
+     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+     */
+    private static Drawable getRoundedCornerTopDrawable(Context context, String displayUniqueId) {
+        final Resources res = context.getResources();
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopDrawableArray);
+        Drawable drawable;
+        if (index >= 0 && index < array.length()) {
+            drawable = array.getDrawable(index);
+        } else {
+            drawable = context.getDrawable(R.drawable.rounded_corner_top);
+        }
+        array.recycle();
+        return drawable;
+    }
+
+    /**
+     * Gets the rounded corner bottom drawable for current display.
+     *
+     * Loads the default config {@link R.drawable#rounded_corner_bottom} if
+     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+     */
+    private static Drawable getRoundedCornerBottomDrawable(
+            Context context, String displayUniqueId) {
+        final Resources res = context.getResources();
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(
+                R.array.config_roundedCornerBottomDrawableArray);
+        Drawable drawable;
+        if (index >= 0 && index < array.length()) {
+            drawable = array.getDrawable(index);
+        } else {
+            drawable = context.getDrawable(R.drawable.rounded_corner_bottom);
+        }
+        array.recycle();
+        return drawable;
+    }
+
     private void updateRoundedCornerView(@BoundsPosition int pos, int id) {
         final View rounded = mOverlays[pos].findViewById(id);
         if (rounded == null) {
@@ -837,6 +937,51 @@
         });
     }
 
+    private void updateRoundedCornerDrawable() {
+        mRoundedCornerDrawable = getRoundedCornerDrawable(mContext, mDisplayUniqueId);
+        mRoundedCornerDrawableTop = getRoundedCornerTopDrawable(mContext, mDisplayUniqueId);
+        mRoundedCornerDrawableBottom = getRoundedCornerBottomDrawable(mContext, mDisplayUniqueId);
+        updateRoundedCornerImageView();
+    }
+
+    private void updateRoundedCornerImageView() {
+        final Drawable top = mRoundedCornerDrawableTop != null
+                ? mRoundedCornerDrawableTop : mRoundedCornerDrawable;
+        final Drawable bottom = mRoundedCornerDrawableBottom != null
+                ? mRoundedCornerDrawableBottom : mRoundedCornerDrawable;
+
+        if (mOverlays == null) {
+            return;
+        }
+        for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+            if (mOverlays[i] == null) {
+                continue;
+            }
+            ((ImageView) mOverlays[i].findViewById(R.id.left)).setImageDrawable(
+                    isTopRoundedCorner(i, R.id.left) ? top : bottom);
+            ((ImageView) mOverlays[i].findViewById(R.id.right)).setImageDrawable(
+                    isTopRoundedCorner(i, R.id.right) ? top : bottom);
+        }
+    }
+
+    private boolean isTopRoundedCorner(@BoundsPosition int pos, int id) {
+        switch (pos) {
+            case BOUNDS_POSITION_LEFT:
+            case BOUNDS_POSITION_RIGHT:
+                if (mRotation == ROTATION_270) {
+                    return id == R.id.left ? false : true;
+                } else {
+                    return id == R.id.left ? true : false;
+                }
+            case BOUNDS_POSITION_TOP:
+                return true;
+            case BOUNDS_POSITION_BOTTOM:
+                return false;
+            default:
+                throw new IllegalArgumentException("Unknown bounds position");
+        }
+    }
+
     private void updateRoundedCornerSize(
             Point sizeDefault,
             Point sizeTop,
@@ -855,21 +1000,10 @@
             if (mOverlays[i] == null) {
                 continue;
             }
-            if (i == BOUNDS_POSITION_LEFT || i == BOUNDS_POSITION_RIGHT) {
-                if (mRotation == ROTATION_270) {
-                    setSize(mOverlays[i].findViewById(R.id.left), sizeBottom);
-                    setSize(mOverlays[i].findViewById(R.id.right), sizeTop);
-                } else {
-                    setSize(mOverlays[i].findViewById(R.id.left), sizeTop);
-                    setSize(mOverlays[i].findViewById(R.id.right), sizeBottom);
-                }
-            } else if (i == BOUNDS_POSITION_TOP) {
-                setSize(mOverlays[i].findViewById(R.id.left), sizeTop);
-                setSize(mOverlays[i].findViewById(R.id.right), sizeTop);
-            } else if (i == BOUNDS_POSITION_BOTTOM) {
-                setSize(mOverlays[i].findViewById(R.id.left), sizeBottom);
-                setSize(mOverlays[i].findViewById(R.id.right), sizeBottom);
-            }
+            setSize(mOverlays[i].findViewById(R.id.left),
+                    isTopRoundedCorner(i, R.id.left) ? sizeTop : sizeBottom);
+            setSize(mOverlays[i].findViewById(R.id.right),
+                    isTopRoundedCorner(i, R.id.right) ? sizeTop : sizeBottom);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index affad7a..3555e8d 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;
@@ -438,6 +452,12 @@
             private boolean mCancelled;
 
             @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                mCallback.onBeginDrag(animView);
+            }
+
+            @Override
             public void onAnimationCancel(Animator animation) {
                 mCancelled = true;
             }
@@ -593,11 +613,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 +639,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 +773,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 +820,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/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index a51e3fc..0893e89 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -499,9 +499,12 @@
     }
 
     private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) {
-        // Sets the initial frame area for the mirror and places it in the center of the display.
-        final int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2
-                + 2 * mMirrorSurfaceMargin;
+        // Sets the initial frame area for the mirror and place it to the given center on the
+        // display.
+        int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2;
+        initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size),
+                initSize);
+        initSize += 2 * mMirrorSurfaceMargin;
         final int initX = centerX - initSize / 2;
         final int initY = centerY - initSize / 2;
         mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
index 81a13a2..4082015 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
@@ -57,7 +57,9 @@
         public void run() {
             mView.removeCallbacks(this);
             mView.show(false /* show */, true /* animate */, () -> {
-                mWindowManager.removeView(mView);
+                if (mView.isAttachedToWindow()) {
+                    mWindowManager.removeView(mView);
+                }
             });
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
index c9e6771..5616a00 100644
--- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
@@ -40,10 +40,10 @@
  * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
  * indicating that restoring is finished for a given user.
  */
-class BackupHelper : BackupAgentHelper() {
+open class BackupHelper : BackupAgentHelper() {
 
     companion object {
-        private const val TAG = "BackupHelper"
+        const val TAG = "BackupHelper"
         internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
         private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
         private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 88c09dc..66085ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -18,62 +18,45 @@
 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;
 import android.widget.TextView;
 
 import androidx.annotation.StyleRes;
+import androidx.annotation.VisibleForTesting;
 
 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;
 import java.lang.annotation.Retention;
 import java.text.NumberFormat;
 
-public class BatteryMeterView extends LinearLayout implements
-        BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
-
+public class BatteryMeterView extends LinearLayout implements DarkReceiver {
 
     @Retention(SOURCE)
     @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
@@ -84,21 +67,14 @@
     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;
@@ -106,19 +82,19 @@
     private Drawable mUnknownStateDrawable;
 
     private DualToneHandler mDualToneHandler;
-    private int mUser;
 
     private int mNonAdaptedSingleToneColor;
     private int mNonAdaptedForegroundColor;
     private int mNonAdaptedBackgroundColor;
 
+    private BatteryEstimateFetcher mBatteryEstimateFetcher;
+
     public BatteryMeterView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
     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);
@@ -131,14 +107,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(
@@ -153,21 +126,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() {
@@ -204,44 +164,6 @@
         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;
@@ -255,42 +177,7 @@
         return false;
     }
 
-    @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
-    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+    void onBatteryLevelChanged(int level, boolean pluggedIn) {
         mDrawable.setCharging(pluggedIn);
         mDrawable.setBatteryLevel(level);
         mCharging = pluggedIn;
@@ -298,8 +185,7 @@
         updatePercentText();
     }
 
-    @Override
-    public void onPowerSaveChanged(boolean isPowerSave) {
+    void onPowerSaveChanged(boolean isPowerSave) {
         mDrawable.setPowerSaveEnabled(isPowerSave);
     }
 
@@ -319,19 +205,28 @@
         updateShowPercent();
     }
 
-    private void updatePercentText() {
+    /**
+     * Sets the fetcher that should be used to get the estimated time remaining for the user's
+     * battery.
+     */
+    void setBatteryEstimateFetcher(BatteryEstimateFetcher fetcher) {
+        mBatteryEstimateFetcher = fetcher;
+    }
+
+    void updatePercentText() {
         if (mBatteryStateUnknown) {
             setContentDescription(getContext().getString(R.string.accessibility_battery_unknown));
             return;
         }
 
-        if (mBatteryController == null) {
+        if (mBatteryEstimateFetcher == null) {
             return;
         }
 
         if (mBatteryPercentView != null) {
             if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
-                mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
+                mBatteryEstimateFetcher.fetchBatteryTimeRemainingEstimate(
+                        (String estimate) -> {
                     if (mBatteryPercentView == null) {
                         return;
                     }
@@ -365,12 +260,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
@@ -398,11 +293,6 @@
         }
     }
 
-    @Override
-    public void onDensityOrFontScaleChanged() {
-        scaleBatteryMeterViews();
-    }
-
     private Drawable getUnknownStateDrawable() {
         if (mUnknownStateDrawable == null) {
             mUnknownStateDrawable = mContext.getDrawable(R.drawable.ic_battery_unknown);
@@ -412,8 +302,7 @@
         return mUnknownStateDrawable;
     }
 
-    @Override
-    public void onBatteryUnknownStateChanged(boolean isUnknown) {
+    void onBatteryUnknownStateChanged(boolean isUnknown) {
         if (mBatteryStateUnknown == isUnknown) {
             return;
         }
@@ -432,7 +321,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();
 
@@ -493,20 +382,15 @@
         pw.println("    mMode: " + mShowPercentMode);
     }
 
-    private final class SettingObserver extends ContentObserver {
-        public SettingObserver(Handler handler) {
-            super(handler);
-        }
+    @VisibleForTesting
+    CharSequence getBatteryPercentViewText() {
+        return mBatteryPercentView.getText();
+    }
 
-        @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();
-            }
-        }
+    /** An interface that will fetch the estimated time remaining for the user's battery. */
+    public interface BatteryEstimateFetcher {
+        void fetchBatteryTimeRemainingEstimate(
+                BatteryController.EstimateFetchCompletion completion);
     }
 }
+
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 27a6b3c..ae9a323 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -15,22 +15,189 @@
  */
 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.BatteryController;
+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 BatteryController mBatteryController;
+
+    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);
+            }
+        }
+    };
+
+    private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
+            new BatteryController.BatteryStateChangeCallback() {
+                @Override
+                public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+                    mView.onBatteryLevelChanged(level, pluggedIn);
+                }
+
+                @Override
+                public void onPowerSaveChanged(boolean isPowerSave) {
+                    mView.onPowerSaveChanged(isPowerSave);
+                }
+
+                @Override
+                public void onBatteryUnknownStateChanged(boolean isUnknown) {
+                    mView.onBatteryUnknownStateChanged(isUnknown);
+                }
+            };
+
+    // 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) {
+    public BatteryMeterViewController(
+            BatteryMeterView view,
+            ConfigurationController configurationController,
+            TunerService tunerService,
+            BroadcastDispatcher broadcastDispatcher,
+            @Main Handler mainHandler,
+            ContentResolver contentResolver,
+            BatteryController batteryController) {
         super(view);
+        mConfigurationController = configurationController;
+        mTunerService = tunerService;
+        mContentResolver = contentResolver;
+        mBatteryController = batteryController;
+
+        mView.setBatteryEstimateFetcher(mBatteryController::getEstimatedTimeRemainingString);
+
+        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();
+        mBatteryController.addCallback(mBatteryStateChangeCallback);
+
+        registerShowBatteryPercentObserver(ActivityManager.getCurrentUser());
+        registerGlobalBatteryUpdateObserver();
+        mCurrentUserTracker.startTracking();
+
+        mView.updateShowPercent();
     }
 
     @Override
     protected void onViewDetached() {
+        mConfigurationController.removeCallback(mConfigurationListener);
+        unsubscribeFromTunerUpdates();
+        mBatteryController.removeCallback(mBatteryStateChangeCallback);
+
+        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 98ad875..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;
         }
     }
 
@@ -191,11 +198,11 @@
 
                 // 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 "error" state
-                mUdfpsIconController.updateState(mState, newState);
+                // Then, activate this icon controller. We need to start in the "idle" state
+                mUdfpsIconController.updateState(STATE_IDLE);
             }
         } else { // Fingerprint
-            mUdfpsIconController.updateState(mState, newState);
+            mUdfpsIconController.updateState(newState);
         }
 
         super.updateState(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 3f61d3c..fd37b35 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -126,6 +126,7 @@
         boolean mCredentialAllowed;
         boolean mSkipIntro;
         long mOperationId;
+        long mRequestId;
         @BiometricMultiSensorMode int mMultiSensorConfig;
     }
 
@@ -172,6 +173,12 @@
             return this;
         }
 
+        /** Unique id for this request. */
+        public Builder setRequestId(long requestId) {
+            mConfig.mRequestId = requestId;
+            return this;
+        }
+
         /** The multi-sensor mode. */
         public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) {
             mConfig.mMultiSensorConfig = multiSensorConfig;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 0ce1846..bcc0530 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -501,7 +501,7 @@
     @Override
     public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
             int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
-            int userId, String opPackageName, long operationId,
+            int userId, long operationId, String opPackageName, long requestId,
             @BiometricMultiSensorMode int multiSensorConfig) {
         @Authenticators.Types final int authenticators = promptInfo.getAuthenticators();
 
@@ -515,6 +515,7 @@
                     + ", credentialAllowed: " + credentialAllowed
                     + ", requireConfirmation: " + requireConfirmation
                     + ", operationId: " + operationId
+                    + ", requestId: " + requestId
                     + ", multiSensorConfig: " + multiSensorConfig);
         }
         SomeArgs args = SomeArgs.obtain();
@@ -526,6 +527,7 @@
         args.argi1 = userId;
         args.arg6 = opPackageName;
         args.arg7 = operationId;
+        args.arg8 = requestId;
         args.argi2 = multiSensorConfig;
 
         boolean skipAnimation = false;
@@ -629,6 +631,7 @@
         if (mCurrentDialog == null) {
             // Could be possible if the caller canceled authentication after credential success
             // but before the client was notified.
+            if (DEBUG) Log.d(TAG, "dialog already gone");
             return;
         }
 
@@ -683,6 +686,7 @@
         final int userId = args.argi1;
         final String opPackageName = (String) args.arg6;
         final long operationId = (long) args.arg7;
+        final long requestId = (long) args.arg8;
         final @BiometricMultiSensorMode int multiSensorConfig = args.argi2;
 
         // Create a new dialog but do not replace the current one yet.
@@ -695,6 +699,7 @@
                 opPackageName,
                 skipAnimation,
                 operationId,
+                requestId,
                 multiSensorConfig);
 
         if (newDialog == null) {
@@ -772,7 +777,7 @@
 
     protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
             int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
-            boolean skipIntro, long operationId,
+            boolean skipIntro, long operationId, long requestId,
             @BiometricMultiSensorMode int multiSensorConfig) {
         return new AuthContainerView.Builder(mContext)
                 .setCallback(this)
@@ -782,11 +787,16 @@
                 .setOpPackageName(opPackageName)
                 .setSkipIntro(skipIntro)
                 .setOperationId(operationId)
+                .setRequestId(requestId)
                 .setMultiSensorConfig(multiSensorConfig)
                 .build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
     }
 
-    interface Callback {
+    /**
+     * AuthController callback used to receive signal for when biometric authenticators are
+     * registered.
+     */
+    public interface Callback {
         /**
          * Called when authenticators are registered. If authenticators are already
          * registered before this call, this callback will never be triggered.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 1df8ad5..45ca708 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -24,6 +24,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.settingslib.Utils
+import com.android.systemui.R
 import com.android.systemui.statusbar.CircleReveal
 import com.android.systemui.statusbar.LightRevealEffect
 import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -59,6 +60,11 @@
     private var faceSensorLocation: PointF? = null
     private var circleReveal: LightRevealEffect? = null
 
+    override fun onInit() {
+        mView.setAlphaInDuration(sysuiContext.resources.getInteger(
+                R.integer.auth_ripple_alpha_in_duration).toLong())
+    }
+
     @VisibleForTesting
     public override fun onViewAttached() {
         updateRippleColor()
@@ -79,7 +85,7 @@
         notificationShadeWindowController.setForcePluginOpen(false, this)
     }
 
-    private fun showRipple(biometricSourceType: BiometricSourceType?) {
+    fun showRipple(biometricSourceType: BiometricSourceType?) {
         if (!keyguardUpdateMonitor.isKeyguardVisible ||
             keyguardUpdateMonitor.userNeedsStrongAuth()) {
             return
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 95ea8100..95d0afa 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -38,6 +38,7 @@
  * launcher.
  */
 class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+    private var alphaInDuration: Long = 0
     private var rippleInProgress: Boolean = false
     private val rippleShader = RippleShader()
     private val ripplePaint = Paint()
@@ -66,47 +67,37 @@
             .toFloat()
     }
 
+    fun setAlphaInDuration(duration: Long) {
+        alphaInDuration = duration
+    }
+
     fun startRipple(onAnimationEnd: Runnable?, lightReveal: LightRevealScrim?) {
         if (rippleInProgress) {
             return // Ignore if ripple effect is already playing
         }
 
         val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
-            interpolator = PathInterpolator(0.4f, 0f, 0f, 1f)
+            interpolator = PathInterpolator(0f, 0f, .2f, 1f)
             duration = RIPPLE_ANIMATION_DURATION
             addUpdateListener { animator ->
                 val now = animator.currentPlayTime
                 rippleShader.progress = animator.animatedValue as Float
                 rippleShader.time = now.toFloat()
 
-                lightReveal?.revealAmount = animator.animatedValue as Float
                 invalidate()
             }
         }
 
-        val revealAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
+        val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply {
             interpolator = rippleAnimator.interpolator
-            startDelay = 10
             duration = rippleAnimator.duration
             addUpdateListener { animator ->
                 lightReveal?.revealAmount = animator.animatedValue as Float
             }
         }
 
-        val alphaInAnimator = ValueAnimator.ofInt(0, 127).apply {
-            duration = 167
-            addUpdateListener { animator ->
-                rippleShader.color = ColorUtils.setAlphaComponent(
-                    rippleShader.color,
-                    animator.animatedValue as Int
-                )
-                invalidate()
-            }
-        }
-
-        val alphaOutAnimator = ValueAnimator.ofInt(127, 0).apply {
-            startDelay = 417
-            duration = 1116
+        val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply {
+            duration = alphaInDuration
             addUpdateListener { animator ->
                 rippleShader.color = ColorUtils.setAlphaComponent(
                     rippleShader.color,
@@ -120,8 +111,7 @@
             playTogether(
                 rippleAnimator,
                 revealAnimator,
-                alphaInAnimator,
-                alphaOutAnimator
+                alphaInAnimator
             )
             addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?) {
@@ -148,7 +138,7 @@
         // the active effect area. Values here should be kept in sync with the
         // animation implementation in the ripple shader.
         val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
-            (1 - rippleShader.progress)) * radius * 1.5f
+            (1 - rippleShader.progress)) * radius * 2f
         canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 69f9004..ae426b6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -43,7 +43,6 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.Trace;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -76,6 +75,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
+import com.android.systemui.util.time.SystemClock;
 
 import java.util.Optional;
 
@@ -125,6 +125,7 @@
     @Nullable private final UdfpsHbmProvider mHbmProvider;
     @NonNull private final KeyguardBypassController mKeyguardBypassController;
     @NonNull private final ConfigurationController mConfigurationController;
+    @NonNull private final SystemClock mSystemClock;
     @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.
@@ -162,7 +163,8 @@
     public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
             new AudioAttributes.Builder()
                     .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                    // vibration will bypass battery saver mode:
+                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
                     .build();
 
     public static final VibrationEffect EFFECT_CLICK =
@@ -449,19 +451,19 @@
                         final String touchInfo = String.format(
                                 "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
                                 minor, major, v, exceedsVelocityThreshold);
-                        final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
+                        final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
                         if (!isIlluminationRequested && !mGoodCaptureReceived &&
                                 !exceedsVelocityThreshold) {
                             onFingerDown((int) event.getRawX(), (int) event.getRawY(), minor,
                                     major);
                             Log.v(TAG, "onTouch | finger down: " + touchInfo);
-                            mTouchLogTime = SystemClock.elapsedRealtime();
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(),
+                            mTouchLogTime = mSystemClock.elapsedRealtime();
+                            mPowerManager.userActivity(mSystemClock.uptimeMillis(),
                                     PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
                             handled = true;
                         } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
                             Log.v(TAG, "onTouch | finger move: " + touchInfo);
-                            mTouchLogTime = SystemClock.elapsedRealtime();
+                            mTouchLogTime = mSystemClock.elapsedRealtime();
                         }
                     } else {
                         Log.v(TAG, "onTouch | finger outside");
@@ -525,7 +527,8 @@
             @NonNull KeyguardBypassController keyguardBypassController,
             @NonNull DisplayManager displayManager,
             @Main Handler mainHandler,
-            @NonNull ConfigurationController configurationController) {
+            @NonNull ConfigurationController configurationController,
+            @NonNull SystemClock systemClock) {
         mContext = context;
         mExecution = execution;
         // TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -561,6 +564,7 @@
                 mainHandler);
         mKeyguardBypassController = keyguardBypassController;
         mConfigurationController = configurationController;
+        mSystemClock = systemClock;
 
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
@@ -703,15 +707,21 @@
         return mCoreLayoutParams;
     }
 
+
     private void onOrientationChanged() {
         // When the configuration changes it's almost always necessary to destroy and re-create
         // the overlay's window to pass it the new LayoutParams.
         // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
         // of whether it is already hidden.
+        final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
         hideUdfpsOverlay();
+
         // If the overlay needs to be shown, this will re-create and show the overlay with the
         // updated LayoutParams. Otherwise, the overlay will remain hidden.
         updateOverlay();
+        if (wasShowingAltAuth) {
+            mKeyguardViewManager.showGenericBouncer(true);
+        }
     }
 
     private void showUdfpsOverlay(@NonNull ServerRequest request) {
@@ -759,6 +769,7 @@
                 UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
                         R.layout.udfps_enroll_view, null);
                 mView.addView(enrollView);
+                enrollView.updateSensorLocation(mSensorProps);
                 return new UdfpsEnrollViewController(
                         enrollView,
                         mServerRequest.mEnrollHelper,
@@ -781,6 +792,8 @@
                         mKeyguardViewMediator,
                         mLockscreenShadeTransitionController,
                         mConfigurationController,
+                        mSystemClock,
+                        mKeyguardStateController,
                         this
                 );
             case IUdfpsOverlayController.REASON_AUTH_BP:
@@ -816,10 +829,14 @@
             Log.v(TAG, "hideUdfpsOverlay | removing window");
             // Reset the controller back to its starting state.
             onFingerUp();
+            boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
             mWindowManager.removeView(mView);
             mView.setOnTouchListener(null);
             mView.setOnHoverListener(null);
             mView.setAnimationViewController(null);
+            if (wasShowingAltAuth) {
+                mKeyguardViewManager.resetAlternateAuth(true);
+            }
             mAccessibilityManager.removeTouchExplorationStateChangeListener(
                     mTouchExplorationStateChangeListener);
             mView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index ea69b1d..d407756 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -43,7 +43,6 @@
     // 1 + SCALE_MAX is the maximum that the moving target will animate to
     private static final float SCALE_MAX = 0.25f;
 
-    @NonNull private final UdfpsEnrollProgressBarDrawable mProgressDrawable;
     @NonNull private final Drawable mMovingTargetFpIcon;
     @NonNull private final Paint mSensorOutlinePaint;
     @NonNull private final Paint mBlueFill;
@@ -62,7 +61,6 @@
     UdfpsEnrollDrawable(@NonNull Context context) {
         super(context);
 
-        mProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, this);
 
         mSensorOutlinePaint = new Paint(0 /* flags */);
         mSensorOutlinePaint.setAntiAlias(true);
@@ -100,8 +98,6 @@
     }
 
     void onEnrollmentProgress(int remaining, int totalSteps) {
-        mProgressDrawable.setEnrollmentProgress(remaining, totalSteps);
-
         if (mEnrollHelper.isCenterEnrollmentComplete()) {
             if (mAnimatorSet != null && mAnimatorSet.isRunning()) {
                 mAnimatorSet.end();
@@ -139,14 +135,8 @@
         }
     }
 
-    void onLastStepAcquired() {
-        mProgressDrawable.onLastStepAcquired();
-    }
-
     @Override
     public void draw(@NonNull Canvas canvas) {
-        mProgressDrawable.draw(canvas);
-
         if (isIlluminationShowing()) {
             return;
         }
@@ -175,11 +165,6 @@
     }
 
     @Override
-    public void onBoundsChange(@NonNull Rect rect) {
-        mProgressDrawable.setBounds(rect);
-    }
-
-    @Override
     public void setAlpha(int alpha) {
         super.setAlpha(alpha);
         mSensorOutlinePaint.setAlpha(alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 6a918a6..19148e3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -50,6 +50,7 @@
     interface Listener {
         void onEnrollmentProgress(int remaining, int totalSteps);
         void onLastStepAcquired();
+        void onEnrollmentHelp();
     }
 
     @NonNull private final Context mContext;
@@ -138,7 +139,9 @@
     }
 
     void onEnrollmentHelp() {
-
+        if (mListener != null) {
+            mListener.onEnrollmentHelp();
+        }
     }
 
     void setListener(Listener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 4195009..373d17c8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.biometrics;
 
+import android.animation.ArgbEvaluator;
 import android.animation.ValueAnimator;
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -41,19 +43,26 @@
     private static final float PROGRESS_BAR_THICKNESS_DP = 12;
 
     @NonNull private final Context mContext;
-    @NonNull private final UdfpsEnrollDrawable mParent;
     @NonNull private final Paint mBackgroundCirclePaint;
     @NonNull private final Paint mProgressPaint;
 
     @Nullable private ValueAnimator mProgressAnimator;
+    @Nullable private ValueAnimator mProgressShowingHelpAnimator;
+    @Nullable private ValueAnimator mProgressHidingHelpAnimator;
+    @ColorInt private final int mProgressColor;
+    @ColorInt private final int mProgressHelpColor;
+    private final int mShortAnimationDuration;
     private float mProgress;
     private int mRotation; // After last step, rotate the progress bar once
     private boolean mLastStepAcquired;
 
-    public UdfpsEnrollProgressBarDrawable(@NonNull Context context,
-            @NonNull UdfpsEnrollDrawable parent) {
+    public UdfpsEnrollProgressBarDrawable(@NonNull Context context) {
         mContext = context;
-        mParent = parent;
+
+        mShortAnimationDuration = context.getResources()
+                .getInteger(com.android.internal.R.integer.config_shortAnimTime);
+        mProgressColor = context.getColor(R.color.udfps_enroll_progress);
+        mProgressHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
 
         mBackgroundCirclePaint = new Paint();
         mBackgroundCirclePaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP));
@@ -74,7 +83,7 @@
         // Progress should not be color extracted
         mProgressPaint = new Paint();
         mProgressPaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP));
-        mProgressPaint.setColor(context.getColor(R.color.udfps_enroll_progress));
+        mProgressPaint.setColor(mProgressColor);
         mProgressPaint.setAntiAlias(true);
         mProgressPaint.setStyle(Paint.Style.STROKE);
         mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
@@ -92,7 +101,9 @@
             return;
         }
 
-        long animationDuration = 150;
+        long animationDuration = mShortAnimationDuration;
+
+        hideEnrollmentHelp();
 
         if (progress == 1.f) {
             animationDuration = 400;
@@ -101,7 +112,7 @@
             rotationAnimator.addUpdateListener(animation -> {
                 Log.d(TAG, "Rotation: " + mRotation);
                 mRotation = (int) animation.getAnimatedValue();
-                mParent.invalidateSelf();
+                invalidateSelf();
             });
             rotationAnimator.start();
         }
@@ -114,11 +125,7 @@
         mProgressAnimator.setDuration(animationDuration);
         mProgressAnimator.addUpdateListener(animation -> {
             mProgress = (float) animation.getAnimatedValue();
-            // Use the parent to invalidate, since it's the one that's attached as the view's
-            // drawable and has its callback set automatically. Invalidating via
-            // `this.invalidateSelf` actually does not invoke draw(), since this drawable's callback
-            // is not really set.
-            mParent.invalidateSelf();
+            invalidateSelf();
         });
         mProgressAnimator.start();
     }
@@ -128,6 +135,46 @@
         mLastStepAcquired = true;
     }
 
+    void onEnrollmentHelp() {
+        if (mProgressShowingHelpAnimator != null || mProgressAnimator == null) {
+            return; // already showing or at 0% (no progress bar visible)
+        }
+
+        if (mProgressHidingHelpAnimator != null && mProgressHidingHelpAnimator.isRunning()) {
+            mProgressHidingHelpAnimator.cancel();
+        }
+        mProgressHidingHelpAnimator = null;
+
+        mProgressShowingHelpAnimator = getProgressColorAnimator(
+                mProgressPaint.getColor(), mProgressHelpColor);
+        mProgressShowingHelpAnimator.start();
+    }
+
+    private void hideEnrollmentHelp() {
+        if (mProgressHidingHelpAnimator != null || mProgressShowingHelpAnimator == null) {
+            return; // already hidden or help never shown
+        }
+
+        if (mProgressShowingHelpAnimator != null && mProgressShowingHelpAnimator.isRunning()) {
+            mProgressShowingHelpAnimator.cancel();
+        }
+        mProgressShowingHelpAnimator = null;
+
+        mProgressHidingHelpAnimator = getProgressColorAnimator(
+                mProgressPaint.getColor(), mProgressColor);
+        mProgressHidingHelpAnimator.start();
+    }
+
+    private ValueAnimator getProgressColorAnimator(@ColorInt int from, @ColorInt int to) {
+        final ValueAnimator animator = ValueAnimator.ofObject(
+                ArgbEvaluator.getInstance(), from, to);
+        animator.setDuration(mShortAnimationDuration);
+        animator.addUpdateListener(animation -> {
+            mProgressPaint.setColor((int) animation.getAnimatedValue());
+        });
+        return animator;
+    }
+
     @Override
     public void draw(@NonNull Canvas canvas) {
         canvas.save();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
index 2cdf49d..d9edef4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -17,9 +17,12 @@
 package com.android.systemui.biometrics;
 
 import android.content.Context;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 
 import androidx.annotation.NonNull;
@@ -32,20 +35,25 @@
  */
 public class UdfpsEnrollView extends UdfpsAnimationView {
     @NonNull private final UdfpsEnrollDrawable mFingerprintDrawable;
+    @NonNull private final UdfpsEnrollProgressBarDrawable mFingerprintProgressDrawable;
     @NonNull private final Handler mHandler;
 
     @NonNull private ImageView mFingerprintView;
+    @NonNull private ImageView mFingerprintProgressView;
 
     public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mFingerprintDrawable = new UdfpsEnrollDrawable(mContext);
+        mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context);
         mHandler = new Handler(Looper.getMainLooper());
     }
 
     @Override
     protected void onFinishInflate() {
         mFingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view);
+        mFingerprintProgressView = findViewById(R.id.udfps_enroll_animation_fp_progress_view);
         mFingerprintView.setImageDrawable(mFingerprintDrawable);
+        mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable);
     }
 
     @Override
@@ -53,15 +61,35 @@
         return mFingerprintDrawable;
     }
 
+    void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
+        View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
+        final int sensorHeight = sensorProps.sensorRadius * 2;
+        final int sensorWidth = sensorHeight;
+        ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
+        params.width = sensorWidth;
+        params.height = sensorHeight;
+        fingerprintAccessibilityView.setLayoutParams(params);
+        fingerprintAccessibilityView.requestLayout();
+    }
+
     void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
         mFingerprintDrawable.setEnrollHelper(enrollHelper);
     }
 
     void onEnrollmentProgress(int remaining, int totalSteps) {
-        mHandler.post(() -> mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps));
+        mHandler.post(() -> {
+            mFingerprintProgressDrawable.setEnrollmentProgress(remaining, totalSteps);
+            mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps);
+        });
     }
 
     void onLastStepAcquired() {
-        mHandler.post(mFingerprintDrawable::onLastStepAcquired);
+        mHandler.post(() -> {
+            mFingerprintProgressDrawable.onLastStepAcquired();
+        });
+    }
+
+    void onEnrollmentHelp() {
+        mHandler.post(mFingerprintProgressDrawable::onEnrollmentHelp);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 54244a1..33fbe7b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -44,6 +44,11 @@
         public void onLastStepAcquired() {
             mView.onLastStepAcquired();
         }
+
+        @Override
+        public void onEnrollmentHelp() {
+            mView.onEnrollmentHelp();
+        }
     };
 
     protected UdfpsEnrollViewController(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index d122610..9015396 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -23,7 +23,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
@@ -68,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);
@@ -94,9 +91,6 @@
                 new KeyPath("**"), LottieProperty.COLOR_FILTER,
                 frameInfo -> new PorterDuffColorFilter(mTextColorPrimary, PorterDuff.Mode.SRC_ATOP)
         );
-
-        mHintAnimator = ObjectAnimator.ofFloat(mLockScreenFp, "progress", 1f, 0f, 1f);
-        mHintAnimator.setDuration(4000);
     }
 
     @Override
@@ -161,6 +155,13 @@
         updateAlpha();
     }
 
+    /**
+     * @return alpha between 0 and 255
+     */
+    int getUnpausedAlpha() {
+        return mAlpha;
+    }
+
     @Override
     protected int updateAlpha() {
         int alpha = super.updateAlpha();
@@ -183,19 +184,11 @@
     }
 
     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.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 102dc41..44ab69f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -20,14 +20,10 @@
 
 import android.annotation.NonNull;
 import android.content.res.Configuration;
-import android.hardware.biometrics.BiometricSourceType;
 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;
@@ -38,7 +34,9 @@
 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.time.SystemClock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -47,31 +45,28 @@
 
 /**
  * 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 SystemClock mSystemClock;
+    @NonNull private final KeyguardStateController mKeyguardStateController;
     @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;
+    private long mLastUdfpsBouncerShowTime = -1;
+    private float mStatusBarExpansion;
+    private boolean mLaunchTransitionFadingAway;
 
     /**
      * hidden amount of pin/pattern/password bouncer
@@ -92,6 +87,8 @@
             @NonNull KeyguardViewMediator keyguardViewMediator,
             @NonNull LockscreenShadeTransitionController transitionController,
             @NonNull ConfigurationController configurationController,
+            @NonNull SystemClock systemClock,
+            @NonNull KeyguardStateController keyguardStateController,
             @NonNull UdfpsController udfpsController) {
         super(view, statusBarStateController, statusBarOptional, dumpManager);
         mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -100,6 +97,8 @@
         mKeyguardViewMediator = keyguardViewMediator;
         mLockScreenShadeTransitionController = transitionController;
         mConfigurationController = configurationController;
+        mSystemClock = systemClock;
+        mKeyguardStateController = keyguardStateController;
         mUdfpsController = udfpsController;
     }
 
@@ -109,12 +108,14 @@
     }
 
     @Override
+    public void onInit() {
+        super.onInit();
+        mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+    }
+
+    @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);
@@ -122,11 +123,16 @@
 
         mUdfpsRequested = false;
 
+        mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
+        mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
         mStatusBarState = mStatusBarStateController.getState();
         mQsExpanded = mKeyguardViewManager.isQsExpanded();
         mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
         mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
         mConfigurationController.addCallback(mConfigurationListener);
+        mStatusBarOptional.ifPresent(
+                statusBar -> statusBar.addExpansionChangedListener(
+                        mStatusBarExpansionChangedListener));
         updateAlpha();
         updatePauseAuth();
 
@@ -137,21 +143,19 @@
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
-        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
         mFaceDetectRunning = false;
 
+        mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
         mStatusBarStateController.removeCallback(mStateListener);
         mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
         mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
         mConfigurationController.removeCallback(mConfigurationListener);
+        mStatusBarOptional.ifPresent(
+                statusBar -> statusBar.removeExpansionChangedListener(
+                        mStatusBarExpansionChangedListener));
         if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
             mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
         }
-
-        if (mCancelDelayedHintRunnable != null) {
-            mCancelDelayedHintRunnable.run();
-            mCancelDelayedHintRunnable = null;
-        }
     }
 
     @Override
@@ -163,9 +167,11 @@
         pw.println("mQsExpanded=" + mQsExpanded);
         pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
         pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
-        pw.println("mAlpha=" + mView.getAlpha());
+        pw.println("mStatusBarExpansion=" + mStatusBarExpansion);
+        pw.println("unpausedAlpha=" + mView.getUnpausedAlpha());
         pw.println("mUdfpsRequested=" + mUdfpsRequested);
         pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
+        pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
     }
 
     /**
@@ -177,10 +183,13 @@
             return false;
         }
 
+        boolean udfpsAffordanceWasNotShowing = shouldPauseAuth();
         mShowingUdfpsBouncer = show;
-        updatePauseAuth();
         if (mShowingUdfpsBouncer) {
-            if (mStatusBarState == StatusBarState.SHADE_LOCKED) {
+            mLastUdfpsBouncerShowTime = mSystemClock.uptimeMillis();
+        }
+        if (mShowingUdfpsBouncer) {
+            if (udfpsAffordanceWasNotShowing) {
                 mView.animateInUdfpsBouncer(null);
             }
 
@@ -193,6 +202,8 @@
         } else {
             mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
         }
+        updateAlpha();
+        updatePauseAuth();
         return true;
     }
 
@@ -212,6 +223,10 @@
             return false;
         }
 
+        if (mLaunchTransitionFadingAway) {
+            return true;
+        }
+
         if (mStatusBarState != KEYGUARD) {
             return true;
         }
@@ -241,43 +256,22 @@
      * If we were previously showing the udfps bouncer, hide it and instead show the regular
      * (pin/pattern/password) bouncer.
      *
-     * Does nothing if we weren't previously showing the udfps bouncer.
+     * Does nothing if we weren't previously showing the UDFPS bouncer.
      */
     private void maybeShowInputBouncer() {
-        if (mShowingUdfpsBouncer) {
+        if (mShowingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) {
             mKeyguardViewManager.showBouncer(true);
             mKeyguardViewManager.resetAlternateAuth(false);
         }
     }
 
-    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();
-        }
+    /**
+     * Whether the udfps bouncer has shown for at least 200ms before allowing touches outside
+     * of the udfps icon area to dismiss the udfps bouncer and show the pin/pattern/password
+     * bouncer.
+     */
+    private boolean hasUdfpsBouncerShownWithMinTime() {
+        return (mSystemClock.uptimeMillis() - mLastUdfpsBouncerShowTime) > 200;
     }
 
     /**
@@ -290,10 +284,13 @@
     }
 
     private void updateAlpha() {
-        // fade icon on transition to showing bouncer
+        // fade icon on transitions to showing the status bar, but if mUdfpsRequested, then
+        // the keyguard is occluded by some application - so instead use the input bouncer
+        // hidden amount to determine the fade
+        float expansion = mUdfpsRequested ? mInputBouncerHiddenAmount : mStatusBarExpansion;
         int alpha = mShowingUdfpsBouncer ? 255
                 : (int) MathUtils.constrain(
-                    MathUtils.map(.5f, .9f, 0f, 255f, mInputBouncerHiddenAmount),
+                    MathUtils.map(.5f, .9f, 0f, 255f, expansion),
                     0f, 255f);
         alpha *= (1.0f - mTransitionToFullShadeProgress);
         mView.setUnpausedAlpha(alpha);
@@ -319,39 +316,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
@@ -373,6 +337,7 @@
                 public void requestUdfps(boolean request, int color) {
                     mUdfpsRequested = request;
                     mView.requestUdfps(request, color);
+                    updateAlpha();
                     updatePauseAuth();
                 }
 
@@ -442,4 +407,23 @@
                     mView.updateColor();
                 }
             };
+
+    private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
+            new StatusBar.ExpansionChangedListener() {
+                @Override
+                public void onExpansionChanged(float expansion, boolean expanded) {
+                    mStatusBarExpansion = expansion;
+                    updateAlpha();
+                }
+            };
+
+    private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
+            new KeyguardStateController.Callback() {
+                @Override
+                public void onLaunchTransitionFadingAwayChanged() {
+                    mLaunchTransitionFadingAway =
+                            mKeyguardStateController.isLaunchTransitionFadingAway();
+                    updatePauseAuth();
+                }
+            };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index e1349f2..40c28fa 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -21,6 +21,7 @@
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE;
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.LOCK_ICON;
 import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
 
 import android.graphics.Point;
@@ -89,7 +90,9 @@
     Result calculateFalsingResult(
             @Classifier.InteractionType int interactionType,
             double historyBelief, double historyConfidence) {
-        if (interactionType == BRIGHTNESS_SLIDER || interactionType == SHADE_DRAG) {
+        if (interactionType == BRIGHTNESS_SLIDER
+                || interactionType == SHADE_DRAG
+                || interactionType == LOCK_ICON) {
             return Result.passed(0);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
index 213d13b..73e5afe 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
@@ -24,8 +24,16 @@
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.KeyguardVisibilityHelper;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+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.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
 
@@ -34,6 +42,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
@@ -45,13 +55,19 @@
     private static final String TAG = "CommunalController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String STATE_LIST_FORMAT = "[%s]";
+    private static final AnimationProperties COMMUNAL_ANIMATION_PROPERTIES =
+            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
 
     private final Executor mMainExecutor;
+    private final CommunalStateController mCommunalStateController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final KeyguardStateController mKeyguardStateController;
     private final StatusBarStateController mStatusBarStateController;
-    private WeakReference<CommunalSource> mLastSource;
+    private WeakReference<CommunalSource> mCurrentSource;
+    private Optional<ShowRequest> mLastRequest = Optional.empty();
     private int mState;
+    private float mQsExpansion;
+    private float mShadeExpansion;
 
     @Retention(RetentionPolicy.RUNTIME)
     @IntDef({STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_BOUNCER_SHOWING, STATE_KEYGUARD_OCCLUDED})
@@ -65,7 +81,42 @@
     // 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 | STATE_BOUNCER_SHOWING | STATE_KEYGUARD_OCCLUDED;
+            STATE_DOZING | STATE_KEYGUARD_OCCLUDED;
+
+    private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+
+    private ViewController<? extends View> mCommunalViewController;
+
+    private static class ShowRequest {
+        private boolean mShouldShow;
+        private WeakReference<CommunalSource> mSource;
+
+        ShowRequest(boolean shouldShow, WeakReference<CommunalSource> source) {
+            mShouldShow = shouldShow;
+            mSource = source;
+        }
+
+        CommunalSource getSource() {
+            return mSource != null ? mSource.get() : null;
+        }
+
+        boolean shouldShow() {
+            return mShouldShow;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof ShowRequest)) return false;
+            ShowRequest that = (ShowRequest) o;
+            return mShouldShow == that.mShouldShow && Objects.equals(getSource(), that.getSource());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mShouldShow, mSource);
+        }
+    }
 
     private KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -111,24 +162,61 @@
 
                     setState(STATE_DOZING, isDozing);
                 }
+
+                @Override
+                public void onStateChanged(int newState) {
+                    updateCommunalViewOccluded();
+                }
             };
 
     @Inject
     protected CommunalHostViewController(@Main Executor mainExecutor,
+            CommunalStateController communalStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             KeyguardStateController keyguardStateController,
+            DozeParameters dozeParameters,
+            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
             StatusBarStateController statusBarStateController, CommunalHostView view) {
         super(view);
+        mCommunalStateController = communalStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mMainExecutor = mainExecutor;
         mKeyguardStateController = keyguardStateController;
         mStatusBarStateController = statusBarStateController;
+        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
+                keyguardStateController, dozeParameters, unlockedScreenOffAnimationController,
+                /* animateYPos= */ false, /* visibleOnCommunal= */ true);
     }
 
-    @Override
-    public void init() {
-        super.init();
+    /**
+     * Set the visibility of the keyguard status view based on some new state.
+     */
+    public void setKeyguardStatusViewVisibility(
+            int statusBarState,
+            boolean keyguardFadingAway,
+            boolean goingToFullShade,
+            int oldStatusBarState) {
+        mKeyguardVisibilityHelper.setViewVisibility(
+                statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState);
+    }
 
+    /**
+     * Set keyguard status view alpha.
+     */
+    public void setAlpha(float alpha) {
+        if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
+            mView.setAlpha(alpha);
+
+            // Some communal view implementations, such as SurfaceViews, do not behave correctly
+            // inheriting the alpha of their parent. Directly set child alpha here to work around
+            // this.
+            for (int i = mView.getChildCount() - 1; i >= 0; --i) {
+                mView.getChildAt(i).setAlpha(alpha);
+            }
+        }
+    }
+    @Override
+    public void onInit() {
         setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
         setState(STATE_DOZING, mStatusBarStateController.isDozing());
     }
@@ -166,6 +254,8 @@
         if (existingState != mState) {
             showSource();
         }
+
+        updateCommunalViewOccluded();
     }
 
     private String describeState(@State int stateFlag) {
@@ -201,18 +291,26 @@
     }
 
     private void showSource() {
+        final ShowRequest request = new ShowRequest(
+                (mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
+                    && (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
+                    && mCurrentSource != null,
+                mCurrentSource);
+
+        if (mLastRequest.isPresent() && Objects.equals(mLastRequest.get(), request)) {
+            return;
+        }
+
+        mLastRequest = Optional.of(request);
+
         // 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);
+                Log.d(TAG, "showSource. currentSource:" + request.getSource());
             }
 
-            if ((mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
-                    && (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
-                    && currentSource != null) {
+            if (request.shouldShow()) {
                 mView.removeAllViews();
 
                 // Make view visible.
@@ -220,8 +318,8 @@
 
                 final Context context = mView.getContext();
 
-                final ListenableFuture<View> listenableFuture =
-                        currentSource.requestCommunalView(context);
+                final ListenableFuture<CommunalSource.CommunalViewResult> listenableFuture =
+                        request.getSource().requestCommunalView(context);
 
                 if (listenableFuture == null) {
                     Log.e(TAG, "could not request communal view");
@@ -230,11 +328,14 @@
 
                 listenableFuture.addListener(() -> {
                     try {
-                        final View view = listenableFuture.get();
-                        view.setLayoutParams(new ViewGroup.LayoutParams(
+                        final CommunalSource.CommunalViewResult result = listenableFuture.get();
+                        result.view.setLayoutParams(new ViewGroup.LayoutParams(
                                 ViewGroup.LayoutParams.MATCH_PARENT,
                                 ViewGroup.LayoutParams.MATCH_PARENT));
-                        mView.addView(view);
+                        mView.addView(result.view);
+
+                        mCommunalViewController = result.viewController;
+                        mCommunalViewController.init();
                     } catch (Exception e) {
                         Log.e(TAG, "could not obtain communal view through callback:" + e);
                     }
@@ -242,6 +343,7 @@
             } else {
                 mView.removeAllViews();
                 mView.setVisibility(View.INVISIBLE);
+                mCommunalStateController.setCommunalViewShowing(false);
             }
         });
     }
@@ -252,7 +354,43 @@
      * @param source The new {@link CommunalSource}, {@code null} if not set.
      */
     public void show(WeakReference<CommunalSource> source) {
-        mLastSource = source;
+        mCurrentSource = source;
         showSource();
     }
+
+    /**
+     * Update position of the view with an optional animation
+     */
+    public void updatePosition(int y, boolean animate) {
+        PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, COMMUNAL_ANIMATION_PROPERTIES,
+                animate);
+    }
+
+    /**
+     * Invoked when the quick settings is expanded.
+     * @param expansionFraction the percentage the QS shade has been expanded.
+     */
+    public void updateQsExpansion(float expansionFraction) {
+        mQsExpansion = expansionFraction;
+        updateCommunalViewOccluded();
+    }
+
+    /**
+     * Invoked when the main shade is expanded.
+     * @param shadeExpansion the percentage the main shade has expanded.
+     */
+    public void updateShadeExpansion(float shadeExpansion) {
+        mShadeExpansion = shadeExpansion;
+        updateCommunalViewOccluded();
+    }
+
+    private void updateCommunalViewOccluded() {
+        final boolean bouncerShowing = (mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING;
+        final int statusBarState = mStatusBarStateController.getState();
+        final boolean shadeExpanded = statusBarState == StatusBarState.SHADE
+                || statusBarState == StatusBarState.SHADE_LOCKED;
+
+        mCommunalStateController.setCommunalViewOccluded(
+                bouncerShowing || shadeExpanded || mQsExpansion > 0.0f || mShadeExpansion > 0.0f);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.java
new file mode 100644
index 0000000..424da0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.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.systemui.communal;
+
+import android.util.Log;
+
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
+
+/**
+ * {@link CommunalHostViewPositionAlgorithm} calculates the position of the communal view given
+ * input such as the notification panel position.
+ */
+public class CommunalHostViewPositionAlgorithm {
+    private static final String TAG = "CommunalPositionAlg";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * @see NotificationPanelViewController#getExpandedFraction()
+     */
+    private float mPanelExpansion;
+
+    /**
+     * Height of {@link CommunalHostView}.
+     */
+    private int mCommunalHeight;
+
+    /**
+     * A data container for the result of the position algorithm.
+     */
+    public static class Result {
+        /**
+         * The y translation of the clock.
+         */
+        public int communalY;
+    }
+
+    /**
+     * Sets the conditions under which the result should be calculated from.
+     * @param panelExpansion The percentage the keyguard panel has been moved upwards.
+     * @param communalHeight The height of the communal panel.
+     */
+    public void setup(float panelExpansion, int communalHeight) {
+        if (DEBUG) {
+            Log.d(TAG, "setup. panelExpansion:" + panelExpansion);
+        }
+        mPanelExpansion = panelExpansion;
+        mCommunalHeight = communalHeight;
+    }
+
+    /**
+     * Calculates the position based on factors input through {link {@link #setup(float, int)}}.
+     * @param result The resulting calculations.
+     */
+    public void run(Result result) {
+        // The panel expansion relates to the keyguard expansion. At full expansion, the communal
+        // view should be aligned at the top (0). Otherwise, it should be shifted offscreen by the
+        // unexpanded amount.
+        result.communalY = (int) ((1 - mPanelExpansion) * -mCommunalHeight);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
index 742e4b1..99c311e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.view.View;
 
+import com.android.systemui.util.ViewController;
+
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -28,13 +30,38 @@
  */
 public interface CommunalSource {
     /**
+     * {@link CommunalViewResult} is handed back from {@link #requestCommunalView(Context)} and
+     * contains the view to be displayed and its associated controller.
+     */
+    class CommunalViewResult {
+        /**
+         * The resulting communal view.
+         */
+        public final View view;
+        /**
+         * The controller for the communal view.
+         */
+        public final ViewController<? extends View> viewController;
+
+        /**
+         * The default constructor for {@link CommunalViewResult}.
+         * @param view The communal view.
+         * @param viewController The communal view's controller.
+         */
+        public CommunalViewResult(View view, ViewController<? extends View> viewController) {
+            this.view = view;
+            this.viewController = viewController;
+        }
+    }
+
+    /**
      * Requests a communal surface that can be displayed inside {@link CommunalHostView}.
      *
      * @param context The {@link View} {@link Context} to build the resulting view from
-     * @return A future that can be listened upon for the resulting {@link View}. The value will be
-     * {@code null} in case of a failure.
+     * @return A future that can be listened upon for the resulting {@link CommunalViewResult}. The
+     * value will be {@code null} in case of a failure.
      */
-    ListenableFuture<View> requestCommunalView(Context context);
+    ListenableFuture<CommunalViewResult> requestCommunalView(Context context);
 
     /**
      * Adds a {@link Callback} to receive future status updates regarding this
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
index 36fc5fa..2244532 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
@@ -16,13 +16,23 @@
 
 package com.android.systemui.communal;
 
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.MainThread;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.settings.SecureSettings;
 
 import com.google.android.collect.Lists;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Iterator;
 
 import javax.inject.Inject;
 
@@ -31,10 +41,15 @@
  */
 @SysUISingleton
 public class CommunalSourceMonitor {
+    private static final String TAG = "CommunalSourceMonitor";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     // A list of {@link Callback} that have registered to receive updates.
     private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
+    private final SecureSettings mSecureSettings;
 
     private CommunalSource mCurrentSource;
+    private boolean mCommunalEnabled;
 
     private CommunalSource.Callback mSourceCallback = new CommunalSource.Callback() {
         @Override
@@ -46,7 +61,22 @@
 
     @VisibleForTesting
     @Inject
-    public CommunalSourceMonitor() {
+    public CommunalSourceMonitor(
+            @MainThread Handler mainThreadHandler,
+            SecureSettings secureSettings) {
+        mSecureSettings = secureSettings;
+
+        ContentObserver settingsObserver = new ContentObserver(mainThreadHandler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                reloadSettings();
+            }
+        };
+        mSecureSettings.registerContentObserverForUser(
+                Settings.Secure.COMMUNAL_MODE_ENABLED,
+                /* notifyForDescendants= */false,
+                settingsObserver, UserHandle.USER_SYSTEM);
+        reloadSettings();
     }
 
     /**
@@ -62,13 +92,8 @@
 
         mCurrentSource = source;
 
-        // If the new source is valid, inform registered Callbacks of its presence.
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            Callback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onSourceAvailable(
-                        mCurrentSource != null ? new WeakReference<>(mCurrentSource) : null);
-            }
+        if (mCommunalEnabled) {
+            executeOnSourceAvailableCallbacks();
         }
 
         // Add callback to be informed when the source disconnects.
@@ -77,6 +102,21 @@
         }
     }
 
+    private void executeOnSourceAvailableCallbacks() {
+        // If the new source is valid, inform registered Callbacks of its presence.
+        Iterator<WeakReference<Callback>> itr = mCallbacks.iterator();
+        while (itr.hasNext()) {
+            Callback cb = itr.next().get();
+            if (cb == null) {
+                itr.remove();
+            } else {
+                cb.onSourceAvailable(
+                        (mCommunalEnabled && mCurrentSource != null) ? new WeakReference<>(
+                                mCurrentSource) : null);
+            }
+        }
+    }
+
     /**
      * Adds a {@link Callback} to receive {@link CommunalSource} updates.
      *
@@ -86,7 +126,7 @@
         mCallbacks.add(new WeakReference<>(callback));
 
         // Inform the callback of any already present CommunalSource.
-        if (mCurrentSource != null) {
+        if (mCommunalEnabled && mCurrentSource != null) {
             callback.onSourceAvailable(new WeakReference<>(mCurrentSource));
         }
     }
@@ -100,6 +140,22 @@
         mCallbacks.removeIf(el -> el.get() == callback);
     }
 
+    private void reloadSettings() {
+        boolean newCommunalEnabled = mSecureSettings.getIntForUser(
+                Settings.Secure.COMMUNAL_MODE_ENABLED,
+                1,
+                UserHandle.USER_SYSTEM) == 1;
+
+        if (DEBUG) {
+            Log.d(TAG, "communal mode settings reloaded with value:" + newCommunalEnabled);
+        }
+
+        if (mCommunalEnabled != newCommunalEnabled) {
+            mCommunalEnabled = newCommunalEnabled;
+            executeOnSourceAvailableCallbacks();
+        }
+    }
+
     /**
      * Interface implemented to be notified when new {@link CommunalSource} become available.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java
new file mode 100644
index 0000000..c72f542
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java
@@ -0,0 +1,125 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.policy.CallbackController;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import javax.inject.Inject;
+
+/**
+ * CommunalStateController enables publishing and listening to communal-related state changes.
+ */
+@SysUISingleton
+public class CommunalStateController implements
+        CallbackController<CommunalStateController.Callback> {
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+    private boolean mCommunalViewOccluded;
+    private boolean mCommunalViewShowing;
+
+    /**
+     * Callback for communal events.
+     */
+    public interface Callback {
+        /**
+         * Called when the visibility of the communal view changes.
+         */
+        default void onCommunalViewShowingChanged() {
+        }
+
+        /**
+         * Called when the occlusion of the communal view changes.
+         */
+        default void onCommunalViewOccludedChanged() {
+        }
+    }
+
+    @VisibleForTesting
+    @Inject
+    public CommunalStateController() {
+    }
+
+    /**
+     * Sets whether the communal view is showing.
+     * @param communalViewShowing {@code true} if the view is showing, {@code false} otherwise.
+     */
+    public void setCommunalViewShowing(boolean communalViewShowing) {
+        if (mCommunalViewShowing == communalViewShowing) {
+            return;
+        }
+
+        mCommunalViewShowing = communalViewShowing;
+
+        final ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
+        for (Callback callback : callbacks) {
+            callback.onCommunalViewShowingChanged();
+        }
+    }
+
+    /**
+     * Sets whether the communal view is occluded (but otherwise still showing).
+     * @param communalViewOccluded {@code true} if the view is occluded, {@code false} otherwise.
+     */
+    public void setCommunalViewOccluded(boolean communalViewOccluded) {
+        if (mCommunalViewOccluded == communalViewOccluded) {
+            return;
+        }
+
+        mCommunalViewOccluded = communalViewOccluded;
+
+        ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
+        for (int i = 0; i < callbacks.size(); i++) {
+            callbacks.get(i).onCommunalViewOccludedChanged();
+        }
+    }
+
+    /**
+     * Returns whether the communal view is showing.
+     * @return {@code true} if the view is showing, {@code false} otherwise.
+     */
+    public boolean getCommunalViewShowing() {
+        return mCommunalViewShowing;
+    }
+
+    /**
+     * Returns whether the communal view is occluded.
+     * @return {@code true} if the view is occluded, {@code false} otherwise.
+     */
+    public boolean getCommunalViewOccluded() {
+        return mCommunalViewOccluded;
+    }
+
+    @Override
+    public void addCallback(@NonNull Callback callback) {
+        Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
+        if (!mCallbacks.contains(callback)) {
+            mCallbacks.add(callback);
+        }
+    }
+
+    @Override
+    public void removeCallback(@NonNull Callback callback) {
+        Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
+        mCallbacks.remove(callback);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalService.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalService.java
deleted file mode 100644
index 7c010a9..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalService.java
+++ /dev/null
@@ -1,62 +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.systemui.communal.service;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.communal.CommunalSourceMonitor;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.shared.communal.ICommunalHost;
-import com.android.systemui.shared.communal.ICommunalSource;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * CommunalService services requests to {@link ICommunalHost}, allowing clients to declare
- * themselves as the source of communal surfaces.
- */
-public class CommunalService extends Service {
-    final Executor mMainExecutor;
-    final CommunalSourceMonitor mMonitor;
-
-    private ICommunalHost.Stub mBinder = new ICommunalHost.Stub() {
-        @Override
-        public void setSource(ICommunalSource source) {
-            mMonitor.setSource(
-                    source != null ? new CommunalSourceImpl(mMainExecutor, source) : null);
-        }
-    };
-
-    @Inject
-    CommunalService(@Main Executor mainExecutor, CommunalSourceMonitor monitor) {
-        mMainExecutor = mainExecutor;
-        mMonitor = monitor;
-    }
-
-    @Nullable
-    @Override
-    public IBinder onBind(Intent intent) {
-        // The service does not expect requests outside ICommunalHost.
-        return mBinder;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
deleted file mode 100644
index d94b8ac5..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
+++ /dev/null
@@ -1,163 +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.systemui.communal.service;
-
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-
-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;
-
-import com.google.android.collect.Lists;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.lang.ref.WeakReference;
-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
- * translated into the proper binder calls.
- */
-public class CommunalSourceImpl implements CommunalSource {
-    private static final String TAG = "CommunalSourceImpl";
-    private static final boolean DEBUG = false;
-    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.
-    private boolean mConnected = true;
-
-    // A list of {@link Callback} that have registered to receive updates.
-    private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
-
-    public CommunalSourceImpl(Executor mainExecutor, ICommunalSource sourceProxy) {
-        mMainExecutor = mainExecutor;
-        mSourceProxy = sourceProxy;
-
-        try {
-            // Track connection status based on proxy lifetime.
-            mSourceProxy.asBinder().linkToDeath(new IBinder.DeathRecipient() {
-                @Override
-                public void binderDied() {
-                    if (DEBUG) {
-                        Log.d(TAG, "Source lost. Clearing reporting disconnect.");
-                    }
-
-                    // Set connection state and inform callbacks.
-                    onDisconnected();
-                }
-            }, 0);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not link to the source proxy death:" + e);
-        }
-    }
-
-    private void onDisconnected() {
-        mConnected = false;
-        for (WeakReference<Callback> cbRef : mCallbacks) {
-            final Callback cb = cbRef.get();
-            if (cb != null) {
-                cb.onDisconnected();
-            }
-        }
-
-        mCallbacks.clear();
-    }
-
-    @Override
-    public ListenableFuture<View> requestCommunalView(Context context) {
-        if (DEBUG) {
-            Log.d(TAG, "Received request for communal view");
-        }
-        ListenableFuture<View> packageFuture =
-                CallbackToFutureAdapter.getFuture(completer -> {
-                    completer.set(new CommunalSurfaceView(context, mMainExecutor, this));
-                    return "CommunalSourceImpl::requestCommunalSurface::getCommunalSurface";
-                });
-
-        return packageFuture;
-    }
-
-    /**
-     * Called internally to request a new {@link android.view.SurfaceControlViewHost.SurfacePackage}
-     * for showing communal content.
-     *
-     * @param hostToken The HostToken necessary to generate a {@link SurfaceControlViewHost}.
-     * @param displayId The id of the display the surface will be shown on.
-     * @param width     The width of the surface.
-     * @param height    The height of the surface.
-     * @return A future that returns the resulting
-     * {@link android.view.SurfaceControlViewHost.SurfacePackage}.
-     */
-    protected ListenableFuture<SurfaceControlViewHost.SurfacePackage> requestCommunalSurface(
-            IBinder hostToken, int displayId, int width, int height) {
-        return CallbackToFutureAdapter.getFuture(completer -> {
-            mSourceProxy.getCommunalSurface(hostToken, width, height, displayId,
-                    new ICommunalSurfaceCallback.Stub() {
-                        @Override
-                        public void onSurface(
-                                SurfaceControlViewHost.SurfacePackage surfacePackage) {
-                            completer.set(surfacePackage);
-                        }
-                    });
-            return "CommunalSourceImpl::requestCommunalSurface::getCommunalSurface";
-        });
-
-    }
-
-    @Override
-    public void addCallback(Callback callback) {
-        mCallbacks.add(new WeakReference<>(callback));
-
-        // If not connected anymore, immediately inform new callback of disconnection and remove.
-        if (!mConnected) {
-            onDisconnected();
-        }
-    }
-
-    @Override
-    public void removeCallback(Callback callback) {
-        mCallbacks.removeIf(el -> el.get() == callback);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
deleted file mode 100644
index 0f013ff..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
+++ /dev/null
@@ -1,235 +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.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;
-import com.android.systemui.SystemUI;
-import com.android.systemui.communal.CommunalSourceMonitor;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.shared.communal.ICommunalSource;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-
-import javax.inject.Inject;
-
-/**
- * The {@link CommunalSourcePrimer} is responsible for priming SystemUI with a pre-configured
- * Communal source. The SystemUI service binds to the component to retrieve the
- * {@link com.android.systemui.communal.CommunalSource}. {@link CommunalSourcePrimer} has no effect
- * if there is no pre-defined value.
- */
-@SysUISingleton
-public class CommunalSourcePrimer extends SystemUI {
-    private static final String TAG = "CommunalSourcePrimer";
-    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);
-            }
-
-            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 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() {
-    }
-
-    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();
-
-        if (DEBUG) {
-            Log.d(TAG, "onBootCompleted. communal source component:" + mComponentName);
-        }
-
-        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(mComponentName);
-
-        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/communal/service/CommunalSurfaceView.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceView.java
deleted file mode 100644
index 67458a8..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceView.java
+++ /dev/null
@@ -1,96 +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.systemui.communal.service;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.SurfaceControlViewHost;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-import androidx.annotation.NonNull;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.concurrent.Executor;
-
-/**
- * {@link CommunalSurfaceView} can be used to display remote surfaces returned by the
- * {@link CommunalService}. The necessary information for the request are derived from the view's
- * events from being attached to the parent container.
- */
-public class CommunalSurfaceView extends SurfaceView {
-    private static final String TAG = "CommunalSurfaceView";
-    private static final boolean DEBUG = false;
-    private final Executor mMainExecutor;
-    private final CommunalSourceImpl mSource;
-
-    public CommunalSurfaceView(Context context, Executor executor, CommunalSourceImpl source) {
-        super(context);
-        mSource = source;
-        mMainExecutor = executor;
-
-        getHolder().addCallback(new SurfaceHolder.Callback() {
-            @Override
-            public void surfaceCreated(@NonNull SurfaceHolder holder) {
-                onSurfaceCreated();
-            }
-
-            @Override
-            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
-                    int height) {
-
-            }
-
-            @Override
-            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
-
-            }
-        });
-    }
-
-    private void onSurfaceCreated() {
-        setWillNotDraw(false);
-
-        final ListenableFuture<SurfaceControlViewHost.SurfacePackage> surfaceFuture =
-                mSource.requestCommunalSurface(this.getHostToken(),
-                        getDisplay().getDisplayId(), getMeasuredWidth(), getMeasuredHeight());
-
-        surfaceFuture.addListener(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    SurfaceControlViewHost.SurfacePackage surfacePackage = surfaceFuture.get();
-
-                    if (DEBUG) {
-                        Log.d(TAG, "Received surface package:" + surfacePackage);
-                    }
-
-                    if (surfacePackage != null) {
-                        setChildSurfacePackage(surfacePackage);
-                        setZOrderOnTop(true);
-                        postInvalidate();
-                    } else {
-                        Log.e(TAG, "couldn't get the surface package");
-                    }
-                } catch (Exception e) {
-                    Log.e(TAG, "An error occurred retrieving the future result:" + e);
-                }
-            }
-        }, mMainExecutor);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index 17bd14c3..fe79110 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -20,7 +20,6 @@
 
 import com.android.systemui.ImageWallpaper;
 import com.android.systemui.SystemUIService;
-import com.android.systemui.communal.service.CommunalService;
 import com.android.systemui.doze.DozeService;
 import com.android.systemui.dump.SystemUIAuxiliaryDumpService;
 import com.android.systemui.keyguard.KeyguardService;
@@ -39,12 +38,6 @@
     /** */
     @Binds
     @IntoMap
-    @ClassKey(CommunalService.class)
-    public abstract Service bindCommunalService(CommunalService service);
-
-    /** */
-    @Binds
-    @IntoMap
     @ClassKey(DozeService.class)
     public abstract Service bindDozeService(DozeService service);
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 2d200e3..e7974bc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -68,21 +68,15 @@
 import com.android.systemui.navigationbar.NavigationBarOverlayController;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.navigationbar.TaskbarDelegate;
-import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.unfold.UnfoldTransitionFactory;
-import com.android.unfold.UnfoldTransitionProgressProvider;
-import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -98,6 +92,9 @@
 import com.android.systemui.theme.ThemeOverlayApplier;
 import com.android.systemui.util.leak.LeakDetector;
 import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.unfold.UnfoldTransitionFactory;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.config.UnfoldTransitionConfig;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.pip.Pip;
 
@@ -196,19 +193,14 @@
     }
 
     /** */
-    @Provides
-    @SysUISingleton
-    public PluginManager providePluginManager(Context context) {
-        return new PluginManagerImpl(context, new PluginInitializerImpl());
-    }
-
-    /** */
     @SysUISingleton
     @Provides
     static ThemeOverlayApplier provideThemeOverlayManager(Context context,
-            @Background Executor bgExecutor, OverlayManager overlayManager,
+            @Background Executor bgExecutor,
+            @Main Executor mainExecutor,
+            OverlayManager overlayManager,
             DumpManager dumpManager) {
-        return new ThemeOverlayApplier(overlayManager, bgExecutor,
+        return new ThemeOverlayApplier(overlayManager, bgExecutor, mainExecutor,
                 context.getString(R.string.launcher_overlayable_package),
                 context.getString(R.string.themepicker_overlayable_package), dumpManager);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index a89c7ac..648f345 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -23,6 +23,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.systemui.dagger.qualifiers.TestHarness;
+import com.android.systemui.plugins.PluginsModule;
 import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
 
 import javax.inject.Singleton;
@@ -47,7 +48,9 @@
  */
 @Module(includes = {
         FrameworkServicesModule.class,
-        GlobalConcurrencyModule.class})
+        GlobalConcurrencyModule.class,
+        PluginsModule.class,
+})
 public class GlobalModule {
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
index d648c94..a3a45fe 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 
-import com.android.systemui.util.concurrency.ThreadFactory;
-
 import javax.inject.Singleton;
 
 import dagger.BindsInstance;
@@ -55,9 +53,4 @@
      * Builder for a SysUIComponent.
      */
     SysUIComponent.Builder getSysUIComponent();
-
-    /**
-     * Build a {@link ThreadFactory}.
-     */
-    ThreadFactory createThreadFactory();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 9cb9a36..0923caaf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -68,6 +68,7 @@
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;
 import com.android.systemui.statusbar.policy.SensorPrivacyController;
 import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
+import com.android.systemui.volume.dagger.VolumeModule;
 
 import javax.inject.Named;
 
@@ -82,7 +83,8 @@
 @Module(includes = {
         MediaModule.class,
         PowerModule.class,
-        QSModule.class
+        QSModule.class,
+        VolumeModule.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 3d90ede..f593ed2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -18,6 +18,7 @@
 
 import android.app.INotificationManager;
 import android.content.Context;
+import android.view.LayoutInflater;
 
 import androidx.annotation.Nullable;
 
@@ -26,6 +27,7 @@
 import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.BootCompleteCache;
 import com.android.systemui.BootCompleteCacheImpl;
+import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.appops.dagger.AppOpsModule;
 import com.android.systemui.assist.AssistModule;
@@ -62,6 +64,7 @@
 import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -70,13 +73,13 @@
 import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
 import com.android.systemui.tuner.dagger.TunerModule;
 import com.android.systemui.user.UserModule;
+import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
 import com.android.systemui.util.dagger.UtilModule;
 import com.android.systemui.util.sensors.SensorModule;
 import com.android.systemui.util.settings.SettingsUtilModule;
 import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.util.time.SystemClockImpl;
-import com.android.systemui.volume.dagger.VolumeModule;
 import com.android.systemui.wallet.dagger.WalletModule;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.wm.shell.bubbles.Bubbles;
@@ -114,7 +117,6 @@
             TunerModule.class,
             UserModule.class,
             UtilModule.class,
-            VolumeModule.class,
             WalletModule.class
         },
         subcomponents = {
@@ -202,4 +204,19 @@
                 groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager,
                 sysuiMainExecutor));
     }
+
+    @Provides
+    @SysUISingleton
+    static StatusBarWindowView providesStatusBarWindowView(Context context,
+            InjectionInflationController injectionInflationController) {
+        StatusBarWindowView view =
+                (StatusBarWindowView) injectionInflationController.injectable(
+                        LayoutInflater.from(context)).inflate(R.layout.super_status_bar,
+                        /* root= */ null);
+        if (view == null) {
+            throw new IllegalStateException(
+                    "R.layout.super_status_bar could not be properly inflated");
+        }
+        return view;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 470d2f3..98d2739 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -31,6 +31,7 @@
 import android.provider.Settings;
 import android.view.Display;
 
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.dagger.BrightnessSensor;
 import com.android.systemui.doze.dagger.DozeScope;
 import com.android.systemui.doze.dagger.WrappedService;
@@ -63,6 +64,7 @@
     private final Optional<Sensor> mLightSensorOptional;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final DozeParameters mDozeParameters;
+    private final DockManager mDockManager;
     private final int[] mSensorToBrightness;
     private final int[] mSensorToScrimOpacity;
     private final int mScreenBrightnessDim;
@@ -87,7 +89,8 @@
             @BrightnessSensor Optional<Sensor> lightSensorOptional, DozeHost host, Handler handler,
             AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
             WakefulnessLifecycle wakefulnessLifecycle,
-            DozeParameters dozeParameters) {
+            DozeParameters dozeParameters,
+            DockManager dockManager) {
         mContext = context;
         mDozeService = service;
         mSensorManager = sensorManager;
@@ -96,6 +99,7 @@
         mDozeParameters = dozeParameters;
         mDozeHost = host;
         mHandler = handler;
+        mDockManager = dockManager;
 
         mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness;
         mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness;
@@ -122,13 +126,20 @@
 
     @Override
     public void onScreenState(int state) {
-        if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
+        boolean isDockedScreenOn = state == Display.STATE_ON && mDockManager.isDocked();
+        if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND
+                || (isDockedScreenOn && shouldRegisterLightSensorWhenScreenOnDocked())) {
             setLightSensorEnabled(true);
         } else {
             setLightSensorEnabled(false);
         }
     }
 
+    private boolean shouldRegisterLightSensorWhenScreenOnDocked() {
+        return !mDozeParameters.brightnessUsesProx()
+                || !mDozeParameters.getSelectivelyRegisterSensorsUsingProx();
+    }
+
     private void onDestroy() {
         setLightSensorEnabled(false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 23c4413..55e6154 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 =
@@ -455,13 +456,24 @@
 
         public void updateListening() {
             if (!mConfigured || mSensor == null) return;
-            if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
-                    && !mRegistered) {
-                mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
-                if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered);
+            if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) {
+                if (!mRegistered) {
+                    mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
+                    if (DEBUG) {
+                        Log.d(TAG, "requestTriggerSensor[" + mSensor
+                                + "] " + mRegistered);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "requestTriggerSensor[" + mSensor
+                                + "] already registered");
+                    }
+                }
             } else if (mRegistered) {
                 final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
-                if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt);
+                if (DEBUG) {
+                    Log.d(TAG, "cancelTriggerSensor[" + mSensor + "] " + rt);
+                }
                 mRegistered = false;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
index 15e3f3a..5c6478e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
@@ -21,8 +21,8 @@
 private const val MILLIS_PER_MINUTES = 1000 * 60f
 private const val BURN_IN_PREVENTION_PERIOD_Y = 521f
 private const val BURN_IN_PREVENTION_PERIOD_X = 83f
-private const val BURN_IN_PREVENTION_PERIOD_SCALE = 180f
-private const val BURN_IN_PREVENTION_PERIOD_PROGRESS = 120f
+private const val BURN_IN_PREVENTION_PERIOD_SCALE = 181f
+private const val BURN_IN_PREVENTION_PERIOD_PROGRESS = 89f
 
 /**
  * Returns the translation offset that should be used to avoid burn in at
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index bfa4780..5b327bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -34,7 +34,7 @@
  * See [DumpHandler] for more information on how and when this information is dumped.
  */
 @SysUISingleton
-class DumpManager @Inject constructor() {
+open class DumpManager @Inject constructor() {
     private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
     private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
index 1fec7a6..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,6 +26,9 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+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;
@@ -54,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
index 5882179..3ff0883 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -19,8 +19,15 @@
 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;
 
@@ -33,11 +40,88 @@
 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() {
@@ -89,6 +173,10 @@
         return mFlagReader.isEnabled(R.bool.flag_new_unlock_swipe_animation);
     }
 
+    public boolean isKeyguardQsUserDetailsShortcutEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_lockscreen_qs_user_detail_shortcut);
+    }
+
     public boolean isSmartSpaceSharedElementTransitionEnabled() {
         return mFlagReader.isEnabled(R.bool.flag_smartspace_shared_element_transition);
     }
@@ -103,8 +191,21 @@
         return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
     }
 
+    /**
+     * Use the new version of the user switcher
+     */
+    public boolean useNewUserSwitcher() {
+        return mFlagReader.isEnabled(R.bool.flag_new_user_switcher);
+    }
+
     /** 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/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
index 28f63b0..6561bd5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
@@ -25,8 +25,12 @@
  * Proxy to make {@link SystemProperties} easily testable.
  */
 @SysUISingleton
-class SystemPropertiesHelper @Inject constructor() {
+open class SystemPropertiesHelper @Inject constructor() {
     fun getBoolean(name: String, default: Boolean): Boolean {
         return SystemProperties.getBoolean(name, default)
     }
+
+    fun set(name: String, value: Int) {
+        SystemProperties.set(name, value.toString())
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
deleted file mode 100644
index 04a0226..0000000
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.globalactions;
-
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.Nullable;
-import android.app.IActivityManager;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.app.trust.TrustManager;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.os.Handler;
-import android.os.UserManager;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.service.dreams.IDreamManager;
-import android.telecom.TelecomManager;
-import android.transition.AutoTransition;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.view.IWindowManager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.lifecycle.LifecycleOwner;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.view.RotationPolicy;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
-import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.telephony.TelephonyListenerManager;
-import com.android.systemui.util.RingerModeTracker;
-import com.android.systemui.util.leak.RotationUtils;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.settings.SecureSettings;
-
-import java.util.Optional;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Helper to show the global actions dialog.  Each item is an {@link Action} that may show depending
- * on whether the keyguard is showing, and whether the device is provisioned.
- * This version includes wallet.
- */
-public class GlobalActionsDialog extends GlobalActionsDialogLite
-        implements DialogInterface.OnDismissListener,
-        DialogInterface.OnShowListener,
-        ConfigurationController.ConfigurationListener,
-        GlobalActionsPanelPlugin.Callbacks,
-        LifecycleOwner {
-
-    private static final String TAG = "GlobalActionsDialog";
-
-    private final LockPatternUtils mLockPatternUtils;
-    private final KeyguardStateController mKeyguardStateController;
-    private final SysUiState mSysUiState;
-    private final ActivityStarter mActivityStarter;
-    private final SysuiColorExtractor mSysuiColorExtractor;
-    private final IStatusBarService mStatusBarService;
-    private final NotificationShadeWindowController mNotificationShadeWindowController;
-    private GlobalActionsPanelPlugin mWalletPlugin;
-
-    @VisibleForTesting
-    boolean mShowLockScreenCards = false;
-
-    private final KeyguardStateController.Callback mKeyguardStateControllerListener =
-            new KeyguardStateController.Callback() {
-        @Override
-        public void onUnlockedChanged() {
-            if (mDialog != null) {
-                ActionsDialog dialog = (ActionsDialog) mDialog;
-                boolean unlocked = mKeyguardStateController.isUnlocked();
-                if (dialog.mWalletViewController != null) {
-                    dialog.mWalletViewController.onDeviceLockStateChanged(!unlocked);
-                }
-
-                if (unlocked) {
-                    dialog.hideLockMessage();
-                }
-            }
-        }
-    };
-
-    private final ContentObserver mSettingsObserver = new ContentObserver(mMainHandler) {
-        @Override
-        public void onChange(boolean selfChange) {
-            onPowerMenuLockScreenSettingsChanged();
-        }
-    };
-
-    /**
-     * @param context everything needs a context :(
-     */
-    @Inject
-    public GlobalActionsDialog(
-            Context context,
-            GlobalActionsManager windowManagerFuncs,
-            AudioManager audioManager,
-            IDreamManager iDreamManager,
-            DevicePolicyManager devicePolicyManager,
-            LockPatternUtils lockPatternUtils,
-            BroadcastDispatcher broadcastDispatcher,
-            TelephonyListenerManager telephonyListenerManager,
-            GlobalSettings globalSettings,
-            SecureSettings secureSettings,
-            @Nullable Vibrator vibrator,
-            @Main Resources resources,
-            ConfigurationController configurationController,
-            ActivityStarter activityStarter,
-            KeyguardStateController keyguardStateController,
-            UserManager userManager,
-            TrustManager trustManager,
-            IActivityManager iActivityManager,
-            @Nullable TelecomManager telecomManager,
-            MetricsLogger metricsLogger,
-            SysuiColorExtractor colorExtractor,
-            IStatusBarService statusBarService,
-            NotificationShadeWindowController notificationShadeWindowController,
-            IWindowManager iWindowManager,
-            @Background Executor backgroundExecutor,
-            UiEventLogger uiEventLogger,
-            RingerModeTracker ringerModeTracker,
-            SysUiState sysUiState,
-            @Main Handler handler,
-            PackageManager packageManager,
-            Optional<StatusBar> statusBarOptional) {
-
-        super(context,
-                windowManagerFuncs,
-                audioManager,
-                iDreamManager,
-                devicePolicyManager,
-                lockPatternUtils,
-                broadcastDispatcher,
-                telephonyListenerManager,
-                globalSettings,
-                secureSettings,
-                vibrator,
-                resources,
-                configurationController,
-                keyguardStateController,
-                userManager,
-                trustManager,
-                iActivityManager,
-                telecomManager,
-                metricsLogger,
-                colorExtractor,
-                statusBarService,
-                notificationShadeWindowController,
-                iWindowManager,
-                backgroundExecutor,
-                uiEventLogger,
-                ringerModeTracker,
-                sysUiState,
-                handler,
-                packageManager,
-                statusBarOptional);
-
-        mLockPatternUtils = lockPatternUtils;
-        mKeyguardStateController = keyguardStateController;
-        mSysuiColorExtractor = colorExtractor;
-        mStatusBarService = statusBarService;
-        mNotificationShadeWindowController = notificationShadeWindowController;
-        mSysUiState = sysUiState;
-        mActivityStarter = activityStarter;
-
-        mKeyguardStateController.addCallback(mKeyguardStateControllerListener);
-
-        // Listen for changes to show pay on the power menu while locked
-        onPowerMenuLockScreenSettingsChanged();
-        mGlobalSettings.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT),
-                false /* notifyForDescendants */,
-                mSettingsObserver);
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-        mKeyguardStateController.removeCallback(mKeyguardStateControllerListener);
-        mGlobalSettings.unregisterContentObserver(mSettingsObserver);
-    }
-
-    /**
-     * Show the global actions dialog (creating if necessary)
-     *
-     * @param keyguardShowing True if keyguard is showing
-     */
-    public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
-            GlobalActionsPanelPlugin walletPlugin) {
-        mWalletPlugin = walletPlugin;
-        super.showOrHideDialog(keyguardShowing, isDeviceProvisioned);
-    }
-
-    /**
-     * Returns the maximum number of power menu items to show based on which GlobalActions
-     * layout is being used.
-     */
-    @VisibleForTesting
-    @Override
-    protected int getMaxShownPowerItems() {
-        return getContext().getResources().getInteger(
-                com.android.systemui.R.integer.power_menu_max_columns);
-    }
-
-    /**
-     * Create the global actions dialog.
-     *
-     * @return A new dialog.
-     */
-    @Override
-    protected ActionsDialogLite createDialog() {
-        initDialogItems();
-
-        ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
-                this::getWalletViewController, mSysuiColorExtractor,
-                mStatusBarService, mNotificationShadeWindowController,
-                mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger(),
-                getStatusBar());
-
-        if (shouldShowLockMessage(dialog)) {
-            dialog.showLockMessage();
-        }
-        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
-        dialog.setOnDismissListener(this);
-        dialog.setOnShowListener(this);
-
-        return dialog;
-    }
-
-    @Nullable
-    private GlobalActionsPanelPlugin.PanelViewController getWalletViewController() {
-        if (mWalletPlugin == null) {
-            return null;
-        }
-        return mWalletPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());
-    }
-
-    /**
-     * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
-     * called when the quick access wallet requests that an intent be started (with lock screen
-     * shown first if needed).
-     */
-    @Override
-    public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
-        mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
-    }
-
-    @Override
-    protected int getEmergencyTextColor(Context context) {
-        return context.getResources().getColor(
-                com.android.systemui.R.color.global_actions_emergency_text);
-    }
-
-    @Override
-    protected int getEmergencyIconColor(Context context) {
-        return getContext().getResources().getColor(
-                com.android.systemui.R.color.global_actions_emergency_text);
-    }
-
-    @Override
-    protected int getEmergencyBackgroundColor(Context context) {
-        return getContext().getResources().getColor(
-                com.android.systemui.R.color.global_actions_emergency_background);
-    }
-
-    @Override
-    protected int getGridItemLayoutResource() {
-        return com.android.systemui.R.layout.global_actions_grid_item_v2;
-    }
-
-    @VisibleForTesting
-    static class ActionsDialog extends ActionsDialogLite {
-
-        private final Provider<GlobalActionsPanelPlugin.PanelViewController> mWalletFactory;
-        @Nullable private GlobalActionsPanelPlugin.PanelViewController mWalletViewController;
-        private ResetOrientationData mResetOrientationData;
-        @VisibleForTesting ViewGroup mLockMessageContainer;
-        private TextView mLockMessage;
-
-        ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter,
-                Provider<GlobalActionsPanelPlugin.PanelViewController> walletFactory,
-                SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
-                NotificationShadeWindowController notificationShadeWindowController,
-                SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
-                MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
-                Optional<StatusBar> statusBarOptional) {
-            super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
-                    adapter, overflowAdapter, sysuiColorExtractor, statusBarService,
-                    notificationShadeWindowController, sysuiState, onRotateCallback,
-                    keyguardShowing, powerAdapter, uiEventLogger, statusBarOptional);
-            mWalletFactory = walletFactory;
-
-            // Update window attributes
-            Window window = getWindow();
-            window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-            window.setLayout(MATCH_PARENT, MATCH_PARENT);
-            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-            window.addFlags(
-                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                            | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
-                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                            | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
-            setTitle(R.string.global_actions);
-            initializeLayout();
-        }
-
-        private boolean isWalletViewAvailable() {
-            return mWalletViewController != null && mWalletViewController.getPanelContent() != null;
-        }
-
-        private void initializeWalletView() {
-            if (mWalletFactory == null) {
-                return;
-            }
-            mWalletViewController = mWalletFactory.get();
-            if (!isWalletViewAvailable()) {
-                return;
-            }
-
-            boolean isLandscapeWalletViewShown = mContext.getResources().getBoolean(
-                    com.android.systemui.R.bool.global_actions_show_landscape_wallet_view);
-
-            int rotation = RotationUtils.getRotation(mContext);
-            boolean rotationLocked = RotationPolicy.isRotationLocked(mContext);
-            if (rotation != RotationUtils.ROTATION_NONE) {
-                if (rotationLocked) {
-                    if (mResetOrientationData == null) {
-                        mResetOrientationData = new ResetOrientationData();
-                        mResetOrientationData.locked = true;
-                        mResetOrientationData.rotation = rotation;
-                    }
-
-                    // Unlock rotation, so user can choose to rotate to portrait to see the panel.
-                    // This call is posted so that the rotation does not change until post-layout,
-                    // otherwise onConfigurationChanged() may not get invoked.
-                    mGlobalActionsLayout.post(() ->
-                            RotationPolicy.setRotationLockAtAngle(
-                                    mContext, false, RotationUtils.ROTATION_NONE));
-
-                    if (!isLandscapeWalletViewShown) {
-                        return;
-                    }
-                }
-            } else {
-                if (!rotationLocked) {
-                    if (mResetOrientationData == null) {
-                        mResetOrientationData = new ResetOrientationData();
-                        mResetOrientationData.locked = false;
-                    }
-                }
-
-                boolean shouldLockRotation = !isLandscapeWalletViewShown;
-                if (rotationLocked != shouldLockRotation) {
-                    // Locks the screen to portrait if the landscape / seascape orientation does not
-                    // show the wallet view, so the user doesn't accidentally hide the panel.
-                    // This call is posted so that the rotation does not change until post-layout,
-                    // otherwise onConfigurationChanged() may not get invoked.
-                    mGlobalActionsLayout.post(() ->
-                            RotationPolicy.setRotationLockAtAngle(
-                            mContext, shouldLockRotation, RotationUtils.ROTATION_NONE));
-                }
-            }
-
-            // Disable rotation suggestions, if enabled
-            setRotationSuggestionsEnabled(false);
-
-            FrameLayout panelContainer =
-                    findViewById(com.android.systemui.R.id.global_actions_wallet);
-            FrameLayout.LayoutParams panelParams =
-                    new FrameLayout.LayoutParams(
-                            FrameLayout.LayoutParams.MATCH_PARENT,
-                            FrameLayout.LayoutParams.MATCH_PARENT);
-            panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
-                    com.android.systemui.R.dimen.global_actions_wallet_top_margin);
-            View walletView = mWalletViewController.getPanelContent();
-            panelContainer.addView(walletView, panelParams);
-            // Smooth transitions when wallet is resized, which can happen when a card is added
-            ViewGroup root = findViewById(com.android.systemui.R.id.global_actions_grid_root);
-            if (root != null) {
-                walletView.addOnLayoutChangeListener((v, l, t, r, b, ol, ot, or, ob) -> {
-                    int oldHeight = ob - ot;
-                    int newHeight = b - t;
-                    if (oldHeight > 0 && oldHeight != newHeight) {
-                        TransitionSet transition = new AutoTransition()
-                                .setDuration(250)
-                                .setOrdering(TransitionSet.ORDERING_TOGETHER);
-                        TransitionManager.beginDelayedTransition(root, transition);
-                    }
-                });
-            }
-        }
-
-        @Override
-        protected int getLayoutResource() {
-            return com.android.systemui.R.layout.global_actions_grid_v2;
-        }
-
-        @Override
-        protected void initializeLayout() {
-            super.initializeLayout();
-            mLockMessageContainer = requireViewById(
-                    com.android.systemui.R.id.global_actions_lock_message_container);
-            mLockMessage = requireViewById(com.android.systemui.R.id.global_actions_lock_message);
-            initializeWalletView();
-            getWindow().setBackgroundDrawable(mBackgroundDrawable);
-        }
-
-        @Override
-        protected void showDialog() {
-            mShowing = true;
-            mNotificationShadeWindowController.setRequestTopUi(true, TAG);
-            mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
-                    .commitUpdate(mContext.getDisplayId());
-
-            ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView();
-            root.setOnApplyWindowInsetsListener((v, windowInsets) -> {
-                root.setPadding(windowInsets.getStableInsetLeft(),
-                        windowInsets.getStableInsetTop(),
-                        windowInsets.getStableInsetRight(),
-                        windowInsets.getStableInsetBottom());
-                return WindowInsets.CONSUMED;
-            });
-
-            mBackgroundDrawable.setAlpha(0);
-            float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
-            ObjectAnimator alphaAnimator =
-                    ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f);
-            alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-            alphaAnimator.setDuration(183);
-            alphaAnimator.addUpdateListener((animation) -> {
-                float animatedValue = animation.getAnimatedFraction();
-                int alpha = (int) (animatedValue * mScrimAlpha * 255);
-                mBackgroundDrawable.setAlpha(alpha);
-            });
-
-            ObjectAnimator xAnimator =
-                    ObjectAnimator.ofFloat(mContainer, "translationX", xOffset, 0f);
-            xAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-            xAnimator.setDuration(350);
-
-            AnimatorSet animatorSet = new AnimatorSet();
-            animatorSet.playTogether(alphaAnimator, xAnimator);
-            animatorSet.start();
-        }
-
-        @Override
-        protected void dismissInternal() {
-            super.dismissInternal();
-        }
-
-        @Override
-        protected void completeDismiss() {
-            dismissWallet();
-            resetOrientation();
-            super.completeDismiss();
-        }
-
-        private void dismissWallet() {
-            if (mWalletViewController != null) {
-                mWalletViewController.onDismissed();
-                // The wallet controller should not be re-used after being dismissed.
-                mWalletViewController = null;
-            }
-        }
-
-        private void resetOrientation() {
-            if (mResetOrientationData != null) {
-                RotationPolicy.setRotationLockAtAngle(mContext, mResetOrientationData.locked,
-                        mResetOrientationData.rotation);
-            }
-            setRotationSuggestionsEnabled(true);
-        }
-
-        @Override
-        public void refreshDialog() {
-            // ensure dropdown menus are dismissed before re-initializing the dialog
-            dismissWallet();
-            super.refreshDialog();
-        }
-
-        void hideLockMessage() {
-            if (mLockMessageContainer.getVisibility() == View.VISIBLE) {
-                mLockMessageContainer.animate().alpha(0).setDuration(150).setListener(
-                        new AnimatorListenerAdapter() {
-                            @Override
-                            public void onAnimationEnd(Animator animation) {
-                                mLockMessageContainer.setVisibility(View.GONE);
-                            }
-                        }).start();
-            }
-        }
-
-        void showLockMessage() {
-            Drawable lockIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_lock);
-            lockIcon.setTint(mContext.getColor(com.android.systemui.R.color.control_primary_text));
-            mLockMessage.setCompoundDrawablesWithIntrinsicBounds(null, lockIcon, null, null);
-            mLockMessageContainer.setVisibility(View.VISIBLE);
-        }
-
-        private static class ResetOrientationData {
-            public boolean locked;
-            public int rotation;
-        }
-    }
-
-    /**
-     * Determines whether or not debug mode has been activated for the Global Actions Panel.
-     */
-    private static boolean isPanelDebugModeEnabled(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED, 0) == 1;
-    }
-
-    /**
-     * Determines whether or not the Global Actions menu should be forced to use the newer
-     * grid-style layout.
-     */
-    private static boolean isForceGridEnabled(Context context) {
-        return isPanelDebugModeEnabled(context);
-    }
-
-    private boolean shouldShowLockMessage(ActionsDialog dialog) {
-        return isWalletAvailableAfterUnlock(dialog);
-    }
-
-    // Temporary while we move items out of the power menu
-    private boolean isWalletAvailableAfterUnlock(ActionsDialog dialog) {
-        boolean isLockedAfterBoot = mLockPatternUtils.getStrongAuthForUser(getCurrentUser().id)
-                == STRONG_AUTH_REQUIRED_AFTER_BOOT;
-        return !mKeyguardStateController.isUnlocked()
-                && (!mShowLockScreenCards || isLockedAfterBoot)
-                && dialog.isWalletViewAvailable();
-    }
-
-    private void onPowerMenuLockScreenSettingsChanged() {
-        mShowLockScreenCards = mSecureSettings.getInt(
-                Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0) != 0;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index b4e0e2f..8603eba 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -84,6 +84,7 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
@@ -108,6 +109,7 @@
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.MultiListLayout;
 import com.android.systemui.MultiListLayout.MultiListAdapter;
 import com.android.systemui.animation.Interpolators;
@@ -171,6 +173,11 @@
     static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
     static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
 
+    // See NotificationManagerService#scheduleDurationReachedLocked
+    private static final long TOAST_FADE_TIME = 333;
+    // See NotificationManagerService.LONG_DELAY
+    private static final int TOAST_VISIBLE_TIME = 3500;
+
     private final Context mContext;
     private final GlobalActionsManager mWindowManagerFuncs;
     private final AudioManager mAudioManager;
@@ -231,6 +238,7 @@
     protected Handler mMainHandler;
     private int mSmallestScreenWidthDp;
     private final Optional<StatusBar> mStatusBarOptional;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     @VisibleForTesting
     public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
@@ -337,7 +345,8 @@
             SysUiState sysUiState,
             @Main Handler handler,
             PackageManager packageManager,
-            Optional<StatusBar> statusBarOptional) {
+            Optional<StatusBar> statusBarOptional,
+            KeyguardUpdateMonitor keyguardUpdateMonitor) {
         mContext = context;
         mWindowManagerFuncs = windowManagerFuncs;
         mAudioManager = audioManager;
@@ -367,6 +376,7 @@
         mMainHandler = handler;
         mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
         mStatusBarOptional = statusBarOptional;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -420,6 +430,10 @@
         return mStatusBarOptional;
     }
 
+    protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
+        return mKeyguardUpdateMonitor;
+    }
+
     /**
      * Show the global actions dialog (creating if necessary)
      *
@@ -651,7 +665,7 @@
                 mAdapter, mOverflowAdapter, mSysuiColorExtractor,
                 mStatusBarService, mNotificationShadeWindowController,
                 mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
-                mStatusBarOptional);
+                mStatusBarOptional, mKeyguardUpdateMonitor, mLockPatternUtils);
 
         dialog.setOnDismissListener(this);
         dialog.setOnShowListener(this);
@@ -2119,6 +2133,8 @@
         private UiEventLogger mUiEventLogger;
         private GestureDetector mGestureDetector;
         private Optional<StatusBar> mStatusBarOptional;
+        private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+        private LockPatternUtils mLockPatternUtils;
 
         protected ViewGroup mContainer;
 
@@ -2172,7 +2188,8 @@
                 NotificationShadeWindowController notificationShadeWindowController,
                 SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
                 MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
-                Optional<StatusBar> statusBarOptional) {
+                Optional<StatusBar> statusBarOptional,
+                KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
             super(context, themeRes);
             mContext = context;
             mAdapter = adapter;
@@ -2186,6 +2203,8 @@
             mKeyguardShowing = keyguardShowing;
             mUiEventLogger = uiEventLogger;
             mStatusBarOptional = statusBarOptional;
+            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+            mLockPatternUtils = lockPatternUtils;
 
             mGestureDetector = new GestureDetector(mContext, mGestureListener);
 
@@ -2304,6 +2323,14 @@
                 mBackgroundDrawable = new ScrimDrawable();
                 mScrimAlpha = 1.0f;
             }
+
+            // If user entered from the lock screen and smart lock was enabled, disable it
+            int user = KeyguardUpdateMonitor.getCurrentUser();
+            boolean userHasTrust = mKeyguardUpdateMonitor.getUserHasTrust(user);
+            if (mKeyguardShowing && userHasTrust) {
+                mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
+                showSmartLockDisabledMessage();
+            }
         }
 
         protected void fixNavBarClipping() {
@@ -2315,6 +2342,37 @@
             contentParent.setClipToPadding(false);
         }
 
+        private void showSmartLockDisabledMessage() {
+            // Since power menu is the top window, make a Toast-like view that will show up
+            View message = LayoutInflater.from(mContext)
+                    .inflate(com.android.systemui.R.layout.global_actions_toast, mContainer, false);
+
+            // Set up animation
+            AccessibilityManager mAccessibilityManager =
+                    (AccessibilityManager) getContext().getSystemService(
+                            Context.ACCESSIBILITY_SERVICE);
+            final int visibleTime = mAccessibilityManager.getRecommendedTimeoutMillis(
+                    TOAST_VISIBLE_TIME, AccessibilityManager.FLAG_CONTENT_TEXT);
+            message.setVisibility(View.VISIBLE);
+            message.setAlpha(0f);
+            mContainer.addView(message);
+
+            // Fade in
+            message.animate()
+                    .alpha(1f)
+                    .setDuration(TOAST_FADE_TIME)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            // Then fade out
+                            message.animate()
+                                    .alpha(0f)
+                                    .setDuration(TOAST_FADE_TIME)
+                                    .setStartDelay(visibleTime);
+                        }
+                    });
+        }
+
         @Override
         protected void onStart() {
             super.onStart();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index a641ad4..c4508e0 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -97,7 +97,7 @@
                 int backgroundAlpha = (int) (ScrimController.BUSY_SCRIM_ALPHA * 255);
                 background.setAlpha(backgroundAlpha);
                 mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
-                        mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
+                        (int) mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
             } else {
                 float backgroundAlpha = mContext.getResources().getFloat(
                         com.android.systemui.R.dimen.shutdown_scrim_behind_alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/idle/DreamHelper.java b/packages/SystemUI/src/com/android/systemui/idle/DreamHelper.java
new file mode 100644
index 0000000..fba1067
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/DreamHelper.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.systemui.idle;
+
+import android.content.Context;
+import android.service.dreams.Sandman;
+
+import javax.inject.Inject;
+
+/**
+ * A helper class to the idle mode for requests related to the
+ * {@link DreamService}.
+ */
+public class DreamHelper {
+    @Inject
+    protected DreamHelper() {
+    }
+
+    /**
+     * Requests the system to start dreaming.
+     *
+     * @param context The context within which the dream request is sent.
+     */
+    public void startDreaming(Context context) {
+        Sandman.startDreamByUserRequest(context);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
index 38af02b..192c4184a 100644
--- a/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
@@ -31,7 +31,6 @@
 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;
@@ -40,6 +39,7 @@
 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.InputChannelCompat;
 import com.android.systemui.shared.system.InputMonitorCompat;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
@@ -63,41 +63,41 @@
     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})
+    @IntDef({STATE_IDLE_MODE_ENABLED, STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_DREAMING,
+            STATE_LOW_LIGHT, STATE_IDLING, STATE_SHOULD_START_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 keyguard is present, even below a dream or AOD. AKA the device is locked.
+    private static final int STATE_KEYGUARD_SHOWING = 1 << 1;
 
-    // Set when the keyguard is showing.
-    private static final int STATE_KEYGUARD_SHOWING = 1 << 2;
+    // Set when the device has entered a dozing / low power state.
+    private static final int STATE_DOZING = 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 has entered a dreaming state, which includes dozing.
+    private static final int STATE_DREAMING = 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;
+    // Set when the device is idling, which is either dozing or dreaming.
+    private static final int STATE_IDLING = 1 << 5;
 
-    // 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;
+    // Set when the controller decides that the device should start idling (either dozing or
+    // dreaming).
+    private static final int STATE_SHOULD_START_IDLING = 1 << 6;
 
     // The aggregate current state.
     private int mState;
     private boolean mIdleModeActive;
     private boolean mLowLightModeActive;
     private boolean mIsMonitoringLowLight;
+    private boolean mIsMonitoringDream;
+
+    // Whether in a state waiting for dozing to complete before starting dreaming.
+    private boolean mDozeToDreamLock = false;
 
     private final Context mContext;
 
@@ -134,15 +134,24 @@
     // Choreographer to use for monitoring input.
     private final Choreographer mChoreographer;
 
+    // Helper class for DreamService related requests.
+    private final DreamHelper mDreamHelper;
+
     // Monitor for tracking touches for activity.
     private InputMonitorCompat mInputMonitor;
 
-    // Delayed callback for enabling idle mode.
+    // Input receiver of touch activities.
+    private InputChannelCompat.InputEventReceiver mInputEventReceiver;
+
+    // Intent filter for receiving dream broadcasts.
+    private IntentFilter mDreamIntentFilter;
+
+    // Delayed callback for starting idling.
     private final Runnable mEnableIdlingCallback = () -> {
         if (DEBUG) {
-            Log.d(TAG, "enabling idle");
+            Log.d(TAG, "time out, should start idling");
         }
-        setState(STATE_IDLING, true);
+        setState(STATE_SHOULD_START_IDLING, true);
     };
 
     private final KeyguardStateController.Callback mKeyguardCallback =
@@ -161,11 +170,13 @@
                 }
             };
 
-    private final BroadcastReceiver mDreamEndedReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mDreamStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
-                setState(STATE_IDLING, false);
+            if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
+                setState(STATE_DREAMING, true);
+            } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+                setState(STATE_DREAMING, false);
             }
         }
     };
@@ -185,7 +196,8 @@
             @Named(IDLE_VIEW) Provider<View> idleViewProvider,
             Choreographer choreographer,
             KeyguardStateController keyguardStateController,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController,
+            DreamHelper dreamHelper) {
         super(view);
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
@@ -196,6 +208,7 @@
         mStatusBarStateController = statusBarStateController;
         mLooper = looper;
         mChoreographer = choreographer;
+        mDreamHelper = dreamHelper;
 
         mState = STATE_KEYGUARD_SHOWING;
 
@@ -226,6 +239,20 @@
     }
 
     private void setState(@State int state, boolean active) {
+        // If waiting for dozing to stop, ignore any state update until dozing is stopped.
+        if (mDozeToDreamLock) {
+            if (state == STATE_DOZING && !active) {
+                if (DEBUG) {
+                    Log.d(TAG, "dozing stopped, now start dreaming");
+                }
+
+                mDozeToDreamLock = false;
+                enableIdleMode(true);
+            }
+
+            return;
+        }
+
         final int oldState = mState;
 
         if (active) {
@@ -234,31 +261,85 @@
             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);
+        // Updates STATE_IDLING.
+        final boolean isIdling = getState(STATE_DOZING) || getState(STATE_DREAMING);
+        if (isIdling) {
+            mState |= STATE_IDLING;
+        } else {
+            mState &= ~STATE_IDLING;
         }
 
-        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);
+        // Updates STATE_SHOULD_START_IDLING.
+        final boolean stoppedIdling = stoppedIdling(oldState);
+        if (stoppedIdling) {
+            mState &= ~STATE_SHOULD_START_IDLING;
+        } else if (shouldStartIdling(oldState)) {
+            mState |= STATE_SHOULD_START_IDLING;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "set " + getStateName(state) + " to " + active);
+            logCurrentState();
+        }
+
+        final boolean wasLowLight = getState(STATE_LOW_LIGHT, oldState);
+        final boolean isLowLight = getState(STATE_LOW_LIGHT);
+        final boolean wasIdling = getState(STATE_IDLING, oldState);
+
+        // When the device is idling and no longer in low light, wake up from dozing, wait till
+        // done, and start dreaming.
+        if (wasLowLight && !isLowLight && wasIdling && isIdling) {
+            if (DEBUG) {
+                Log.d(TAG, "idling and no longer in low light, stop dozing");
+            }
+
+            mDozeToDreamLock = true;
+
+            enableLowLightMode(false);
+            return;
+        }
+
+        final boolean inCommunalMode = getState(STATE_IDLE_MODE_ENABLED)
+                && getState(STATE_KEYGUARD_SHOWING);
+
+        enableDreamMonitoring(inCommunalMode);
+        enableLowLightMonitoring(inCommunalMode);
+        enableIdleMonitoring(inCommunalMode && !getState(STATE_IDLING));
+        enableIdleMode(inCommunalMode && !getState(STATE_LOW_LIGHT)
+                && getState(STATE_SHOULD_START_IDLING));
+        enableLowLightMode(inCommunalMode && !stoppedIdling && getState(STATE_LOW_LIGHT));
+    }
+
+    private void enableDreamMonitoring(boolean enable) {
+        if (mIsMonitoringDream == enable) {
+            return;
+        }
+
+        mIsMonitoringDream = enable;
+
+        if (DEBUG) {
+            Log.d(TAG, (enable ? "enable" : "disable") + " dream monitoring");
+        }
+
+        if (mDreamIntentFilter == null) {
+            mDreamIntentFilter = new IntentFilter();
+            mDreamIntentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
+            mDreamIntentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
+        }
+
+        if (enable) {
+            mBroadcastDispatcher.registerReceiver(mDreamStateReceiver, mDreamIntentFilter);
+        } else {
+            mBroadcastDispatcher.unregisterReceiver(mDreamStateReceiver);
+        }
     }
 
     private void enableIdleMonitoring(boolean enable) {
-        if (enable && mInputMonitor == null) {
+        if (enable && mInputMonitor == null && mInputEventReceiver == null) {
             if (DEBUG) {
                 Log.d(TAG, "enable idle monitoring");
             }
@@ -268,7 +349,7 @@
 
             // Monitor - any input should reset timer
             mInputMonitor = mInputMonitorFactory.getInputMonitor(INPUT_MONITOR_IDENTIFIER);
-            mInputMonitor.getInputReceiver(mLooper, mChoreographer,
+            mInputEventReceiver = mInputMonitor.getInputReceiver(mLooper, mChoreographer,
                     v -> {
                         if (DEBUG) {
                             Log.d(TAG, "touch detected, resetting timeout");
@@ -281,7 +362,7 @@
                         mCancelEnableIdling = mDelayableExecutor.executeDelayed(
                                 mEnableIdlingCallback, mIdleTimeout);
                     });
-        } else if (!enable && mInputMonitor != null) {
+        } else if (!enable && mInputMonitor != null && mInputEventReceiver != null) {
             if (DEBUG) {
                 Log.d(TAG, "disable idle monitoring");
             }
@@ -291,7 +372,9 @@
                 mCancelEnableIdling = null;
             }
 
+            mInputEventReceiver.dispose();
             mInputMonitor.dispose();
+            mInputEventReceiver = null;
             mInputMonitor = null;
         }
     }
@@ -302,22 +385,14 @@
         }
 
         if (DEBUG) {
-            Log.d(TAG, "enable idle mode:" + enable);
+            Log.d(TAG, (enable ? "enable" : "disable") + " idle mode");
         }
 
         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);
+            mDreamHelper.startDreaming(mContext);
         }
     }
 
@@ -329,11 +404,11 @@
         mIsMonitoringLowLight = enable;
 
         if (mIsMonitoringLowLight) {
-            if (DEBUG) Log.d(TAG, "Enabling low light monitoring.");
+            if (DEBUG) Log.d(TAG, "enable low light monitoring");
             mSensorManager.registerListener(this /*listener*/, mSensor,
                     SensorManager.SENSOR_DELAY_NORMAL);
         } else {
-            if (DEBUG) Log.d(TAG, "Disabling low light monitoring.");
+            if (DEBUG) Log.d(TAG, "disable low light monitoring");
             mSensorManager.unregisterListener(this);
         }
     }
@@ -346,13 +421,13 @@
         mLowLightModeActive = enable;
 
         if (mLowLightModeActive) {
-            if (DEBUG) Log.d(TAG, "Entering low light, start dozing.");
+            if (DEBUG) Log.d(TAG, "enter 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.");
+            if (DEBUG) Log.d(TAG, "exit low light, stop dozing");
             mPowerManager.wakeUp(SystemClock.uptimeMillis(),
                     PowerManager.WAKE_REASON_APPLICATION, "Exit low light condition");
         }
@@ -381,8 +456,12 @@
             return;
         }
 
-        final boolean isLowLight = event.values[0] < 10;
-        setState(STATE_LOW_LIGHT, isLowLight);
+        final boolean shouldBeLowLight = event.values[0] < 10;
+        final boolean isLowLight = getState(STATE_LOW_LIGHT);
+
+        if (shouldBeLowLight != isLowLight) {
+            setState(STATE_LOW_LIGHT, shouldBeLowLight);
+        }
     }
 
     @Override
@@ -391,4 +470,62 @@
             Log.d(TAG, "onAccuracyChanged accuracy=" + accuracy);
         }
     }
+
+    // Returns whether the device just stopped idling by comparing the previous state with the
+    // current one.
+    private boolean stoppedIdling(int oldState) {
+        // The device stopped idling if it's no longer dreaming or dozing.
+        return !getState(STATE_DOZING) && !getState(STATE_DREAMING)
+                && (getState(STATE_DOZING, oldState) || getState(STATE_DREAMING, oldState));
+    }
+
+    private boolean shouldStartIdling(int oldState) {
+        // Should start idling immediately if the device went in low light environment.
+        return !getState(STATE_LOW_LIGHT, oldState) && getState(STATE_LOW_LIGHT);
+    }
+
+    private String getStateName(@State int state) {
+        switch (state) {
+            case STATE_IDLE_MODE_ENABLED:
+                return "STATE_IDLE_MODE_ENABLED";
+            case STATE_KEYGUARD_SHOWING:
+                return "STATE_KEYGUARD_SHOWING";
+            case STATE_DOZING:
+                return "STATE_DOZING";
+            case STATE_DREAMING:
+                return "STATE_DREAMING";
+            case STATE_LOW_LIGHT:
+                return "STATE_LOW_LIGHT";
+            case STATE_IDLING:
+                return "STATE_IDLING";
+            case STATE_SHOULD_START_IDLING:
+                return "STATE_SHOULD_START_IDLING";
+            default:
+                return "STATE_UNKNOWN";
+        }
+    }
+
+    private boolean getState(@State int state) {
+        return getState(state, mState);
+    }
+
+    private boolean getState(@State int state, int oldState) {
+        return (oldState & state) == state;
+    }
+
+    private String getStateLog(@State int state) {
+        return getStateName(state) + " = " + getState(state);
+    }
+
+    private void logCurrentState() {
+        Log.d(TAG, "current state: {\n"
+                + "\t" + getStateLog(STATE_IDLE_MODE_ENABLED) + "\n"
+                + "\t" + getStateLog(STATE_KEYGUARD_SHOWING) + "\n"
+                + "\t" + getStateLog(STATE_DOZING) + "\n"
+                + "\t" + getStateLog(STATE_DREAMING) + "\n"
+                + "\t" + getStateLog(STATE_LOW_LIGHT) + "\n"
+                + "\t" + getStateLog(STATE_IDLING) + "\n"
+                + "\t" + getStateLog(STATE_SHOULD_START_IDLING) + "\n"
+                + "}");
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 0b8c635..a5dd6a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -21,6 +21,7 @@
 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_GOING_AWAY;
 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;
@@ -33,6 +34,7 @@
 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.TransitionOldType;
 import static android.view.WindowManager.TransitionType;
 import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
@@ -65,6 +67,7 @@
 import android.view.WindowManagerPolicyConstants;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 import android.window.TransitionInfo;
 
@@ -170,8 +173,9 @@
     }
 
     private static @TransitionOldType int getTransitionOldType(@TransitionType int type,
-            RemoteAnimationTarget[] apps) {
-        if (type == TRANSIT_KEYGUARD_GOING_AWAY) {
+            @TransitionFlags int flags, RemoteAnimationTarget[] apps) {
+        if (type == TRANSIT_KEYGUARD_GOING_AWAY
+                || (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) {
             return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
                     : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
         } else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
@@ -200,7 +204,7 @@
                     t.setAlpha(change.getLeash(), 1.0f);
                 }
                 t.apply();
-                runner.onAnimationStart(getTransitionOldType(info.getType(), apps),
+                runner.onAnimationStart(getTransitionOldType(info.getType(), info.getFlags(), apps),
                         apps, wallpapers, nonApps,
                         new IRemoteAnimationFinishedCallback.Stub() {
                             @Override
@@ -232,8 +236,9 @@
             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));
+                f.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+                shellTransitions.registerRemote(f,
+                        new RemoteTransition(wrap(mExitAnimationRunner)));
             }
             if (sEnableRemoteKeyguardOccludeAnimation) {
                 Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
@@ -252,7 +257,7 @@
                 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);
+                shellTransitions.registerRemote(f, new RemoteTransition(mOccludeAnimation));
 
                 // Now register for un-occlude.
                 f = new TransitionFilter();
@@ -272,7 +277,7 @@
                 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);
+                shellTransitions.registerRemote(f, new RemoteTransition(mUnoccludeAnimation));
             }
         } else {
             RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 85f2366..2817718 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2603,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);
@@ -2759,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);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
index d8905a0..f25ec55 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
@@ -16,8 +16,8 @@
 package com.android.systemui.keyguard
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.unfold.updates.screen.ScreenStatusProvider
-import com.android.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
 import javax.inject.Inject
 
 @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 2facf3d..db5dbb0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -212,14 +212,32 @@
                 isSsReactivated: Boolean
             ) {
                 if (addOrUpdatePlayer(key, oldKey, data)) {
+                    // Log card received if a new resumable media card is added
                     MediaPlayerData.getMediaPlayer(key)?.let {
                         logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                                 it.mInstanceId,
+                                it.mUid,
                                 /* isRecommendationCard */ false,
                                 it.surfaceForSmartspaceLogging,
                                 rank = MediaPlayerData.getMediaPlayerIndex(key))
                     }
                 }
+                if (isSsReactivated) {
+                    // If resumable media is reactivated by headphone connection, update instance
+                    // id for each card and log a receive event.
+                    MediaPlayerData.players().forEachIndexed { index, it ->
+                        if (it.recommendationViewHolder == null) {
+                            it.mInstanceId = SmallHash.hash(it.mUid +
+                                    systemClock.currentTimeMillis().toInt())
+                            logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+                                    it.mInstanceId,
+                                    it.mUid,
+                                    /* isRecommendationCard */ false,
+                                    it.surfaceForSmartspaceLogging,
+                                    rank = index)
+                        }
+                    }
+                }
                 if (mediaCarouselScrollHandler.visibleToUser &&
                         isSsReactivated && !mediaCarouselScrollHandler.qsExpanded) {
                     // It could happen that reactived media player isn't visible to user because
@@ -252,6 +270,7 @@
                     MediaPlayerData.getMediaPlayer(key)?.let {
                         logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                                 it.mInstanceId,
+                                it.mUid,
                                 /* isRecommendationCard */ true,
                                 it.surfaceForSmartspaceLogging,
                                 rank = MediaPlayerData.getMediaPlayerIndex(key))
@@ -261,6 +280,7 @@
                                 MediaPlayerData.getMediaPlayerIndex(key)) {
                             logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
                                     it.mInstanceId,
+                                    it.mUid,
                                     /* isRecommendationCard */ true,
                                     it.surfaceForSmartspaceLogging)
                         }
@@ -339,9 +359,9 @@
             if (activeMediaIndex != -1) {
                 previousVisiblePlayerKey?.let {
                     val previousVisibleIndex = MediaPlayerData.playerKeys()
-                        .indexOfFirst { key -> it == key }
+                            .indexOfFirst { key -> it == key }
                     mediaCarouselScrollHandler
-                        .scrollToPlayer(previousVisibleIndex, activeMediaIndex)
+                            .scrollToPlayer(previousVisibleIndex, activeMediaIndex)
                 } ?: {
                     mediaCarouselScrollHandler.scrollToPlayer(destIndex = activeMediaIndex)
                 }
@@ -355,11 +375,11 @@
         MediaPlayerData.moveIfExists(oldKey, key)
         val existingPlayer = MediaPlayerData.getMediaPlayer(key)
         val curVisibleMediaKey = MediaPlayerData.playerKeys()
-            .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+                .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
         if (existingPlayer == null) {
             var newPlayer = mediaControlPanelFactory.get()
             newPlayer.attachPlayer(
-                PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
+                    PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
             newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
             val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT)
@@ -407,14 +427,14 @@
 
         var newRecs = mediaControlPanelFactory.get()
         newRecs.attachRecommendation(
-            RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent))
+                RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent))
         newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
         val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-            ViewGroup.LayoutParams.WRAP_CONTENT)
+                ViewGroup.LayoutParams.WRAP_CONTENT)
         newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
         newRecs.bindRecommendation(data.copy(backgroundColor = bgColor))
         val curVisibleMediaKey = MediaPlayerData.playerKeys()
-            .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+                .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
         MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize, systemClock)
         updatePlayerToState(newRecs, noAnimation = true)
         reorderAllPlayers(curVisibleMediaKey)
@@ -462,7 +482,7 @@
                 removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
                 smartspaceMediaData?.let {
                     addSmartspaceMediaRecommendations(
-                        it.targetId, it, MediaPlayerData.shouldPrioritizeSs)
+                            it.targetId, it, MediaPlayerData.shouldPrioritizeSs)
                 }
             } else {
                 removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
@@ -585,7 +605,7 @@
                 ?: endShowsActive
         if (currentlyShowingOnlyActive != endShowsActive ||
                 ((currentTransitionProgress != 1.0f && currentTransitionProgress != 0.0f) &&
-                            startShowsActive != endShowsActive)) {
+                        startShowsActive != endShowsActive)) {
             // Whenever we're transitioning from between differing states or the endstate differs
             // we reset the translation
             currentlyShowingOnlyActive = endShowsActive
@@ -696,23 +716,43 @@
             }
             logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
                     mediaControlPanel.mInstanceId,
+                    mediaControlPanel.mUid,
                     isRecommendationCard,
                     mediaControlPanel.surfaceForSmartspaceLogging)
         }
     }
 
     @JvmOverloads
+    /**
+     * Log Smartspace events
+     *
+     * @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN)
+     * @param instanceId id to uniquely identify a card, e.g. each headphone generates a new
+     * instanceId
+     * @param uid uid for the application that media comes from
+     * @param isRecommendationCard whether the card is media recommendation
+     * @param surface which display surface the media card is on (e.g. lockscreen, shade)
+     * @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
+     * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
+     * @param interactedSubcardCardinality how many media items were shown to the user when there
+     * is user interaction
+     * @param rank the rank for media card in the media carousel, starting from 0
+     *
+     */
     fun logSmartspaceCardReported(
         eventId: Int,
         instanceId: Int,
+        uid: Int,
         isRecommendationCard: Boolean,
         surface: Int,
+        interactedSubcardRank: Int = 0,
+        interactedSubcardCardinality: Int = 0,
         rank: Int = mediaCarouselScrollHandler.visibleMediaIndex
     ) {
         // Only log media resume card when Smartspace data is available
         if (!isRecommendationCard &&
-                        !mediaManager.smartspaceMediaData.isActive &&
-                                MediaPlayerData.smartspaceMediaData == null) {
+                !mediaManager.smartspaceMediaData.isActive &&
+                MediaPlayerData.smartspaceMediaData == null) {
             return
         }
 
@@ -720,13 +760,20 @@
         SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
                 eventId,
                 instanceId,
-                if (isRecommendationCard)
-                    SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS
-                else
-                    SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_RESUME_MEDIA,
+                // Deprecated, replaced with AiAi feature type so we don't need to create logging
+                // card type for each new feature.
+                SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
                 surface,
                 rank,
-                mediaContent.getChildCount())
+                mediaContent.getChildCount(),
+                if (isRecommendationCard)
+                    15 // MEDIA_RECOMMENDATION
+                else
+                    31, // MEDIA_RESUME
+                uid,
+                interactedSubcardRank,
+                interactedSubcardCardinality
+        )
         /* ktlint-disable max-line-length */
     }
 
@@ -738,18 +785,20 @@
         if (!recommendation.isEmpty()) {
             logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
                     recommendation.get(0).mInstanceId,
+                    recommendation.get(0).mUid,
                     true,
                     recommendation.get(0).surfaceForSmartspaceLogging,
-            /* rank */-1)
+                    rank = -1)
         } else {
             val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
             if (MediaPlayerData.players().size > visibleMediaIndex) {
                 val player = MediaPlayerData.players().elementAt(visibleMediaIndex)
                 logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
                         player.mInstanceId,
-                false,
+                        player.mUid,
+                        false,
                         player.surfaceForSmartspaceLogging,
-                /* rank */-1)
+                        rank = -1)
             }
         }
         mediaManager.onSwipeToDismiss()
@@ -768,7 +817,7 @@
 @VisibleForTesting
 internal object MediaPlayerData {
     private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
-        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
+            emptyList(), emptyList(), "INVALID", null, null, null, true, null)
     // Whether should prioritize Smartspace card.
     internal var shouldPrioritizeSs: Boolean = false
         private set
@@ -776,18 +825,18 @@
         private set
 
     data class MediaSortKey(
-        // Whether the item represents a Smartspace media recommendation.
+            // Whether the item represents a Smartspace media recommendation.
         val isSsMediaRec: Boolean,
         val data: MediaData,
         val updateTime: Long = 0
     )
 
     private val comparator =
-        compareByDescending<MediaSortKey> { it.data.isPlaying }
-            .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
-            .thenByDescending { it.data.isLocalSession }
-            .thenByDescending { !it.data.resumption }
-            .thenByDescending { it.updateTime }
+            compareByDescending<MediaSortKey> { it.data.isPlaying }
+                    .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
+                    .thenByDescending { it.data.isLocalSession }
+                    .thenByDescending { !it.data.resumption }
+                    .thenByDescending { it.updateTime }
 
     private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator)
     private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf()
@@ -888,4 +937,4 @@
         }
         return false
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 15a7083..c125612 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -33,6 +33,7 @@
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
+import android.os.Process;
 import android.text.Layout;
 import android.util.Log;
 import android.view.View;
@@ -111,6 +112,9 @@
     private int mAlbumArtSize;
     // Instance id for logging purpose.
     protected int mInstanceId = -1;
+    // Uid for the media app.
+    protected int mUid = Process.INVALID_UID;
+    private int mSmartspaceMediaItemsCount;
     private MediaCarouselController mMediaCarouselController;
     private final MediaOutputDialogFactory mMediaOutputDialogFactory;
 
@@ -266,7 +270,13 @@
         }
         mKey = key;
         MediaSession.Token token = data.getToken();
-        mInstanceId = SmallHash.hash(data.getPackageName());
+        PackageManager packageManager = mContext.getPackageManager();
+        try {
+            mUid = packageManager.getApplicationInfo(data.getPackageName(), 0 /* flags */).uid;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Unable to look up package name", e);
+        }
+        mInstanceId = SmallHash.hash(mUid);
 
         mBackgroundColor = data.getBackgroundColor();
         if (mToken == null || !mToken.equals(token)) {
@@ -360,27 +370,16 @@
 
         final MediaDeviceData device = data.getDevice();
         final int seamlessId = mPlayerViewHolder.getSeamless().getId();
-        final int seamlessFallbackId = mPlayerViewHolder.getSeamlessFallback().getId();
-        final boolean showFallback = device != null && !device.getEnabled();
-        final int seamlessFallbackVisibility = showFallback ? View.VISIBLE : View.GONE;
-        mPlayerViewHolder.getSeamlessFallback().setVisibility(seamlessFallbackVisibility);
-        expandedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility);
-        collapsedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility);
-        final int seamlessVisibility = showFallback ? View.GONE : View.VISIBLE;
-        mPlayerViewHolder.getSeamless().setVisibility(seamlessVisibility);
-        expandedSet.setVisibility(seamlessId, seamlessVisibility);
-        collapsedSet.setVisibility(seamlessId, seamlessVisibility);
-        final float seamlessAlpha = data.getResumption() ? DISABLED_ALPHA : 1.0f;
+        // Disable clicking on output switcher for invalid devices and resumption controls
+        final boolean seamlessDisabled = (device != null && !device.getEnabled())
+                || data.getResumption();
+        final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f;
         expandedSet.setAlpha(seamlessId, seamlessAlpha);
         collapsedSet.setAlpha(seamlessId, seamlessAlpha);
-        // Disable clicking on output switcher for resumption controls.
-        mPlayerViewHolder.getSeamless().setEnabled(!data.getResumption());
+        mPlayerViewHolder.getSeamless().setEnabled(!seamlessDisabled);
         String deviceString = null;
-        if (showFallback) {
-            iconView.setImageDrawable(null);
-        } else if (device != null) {
+        if (device != null && device.getEnabled()) {
             Drawable icon = device.getIcon();
-            iconView.setVisibility(View.VISIBLE);
             if (icon instanceof AdaptiveIcon) {
                 AdaptiveIcon aIcon = (AdaptiveIcon) icon;
                 aIcon.setBackgroundColor(mBackgroundColor);
@@ -391,10 +390,9 @@
             deviceString = device.getName();
         } else {
             // Reset to default
-            Log.w(TAG, "device is null. Not binding output chip.");
-            iconView.setVisibility(View.GONE);
-            deviceString = mContext.getString(
-                    com.android.internal.R.string.ext_media_seamless_action);
+            Log.w(TAG, "Device is null or not enabled: " + device + ", not binding output chip.");
+            iconView.setImageResource(R.drawable.ic_media_home_devices);
+            deviceString =  mContext.getString(R.string.media_seamless_other_device);
         }
         deviceName.setText(deviceString);
         seamlessView.setContentDescription(deviceString);
@@ -531,10 +529,11 @@
         }
 
         // Set up recommendation card's header.
-        ApplicationInfo applicationInfo = null;
+        ApplicationInfo applicationInfo;
         try {
             applicationInfo = mContext.getPackageManager()
                     .getApplicationInfo(data.getPackageName(), 0 /* flags */);
+            mUid = applicationInfo.uid;
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "Fail to get media recommendation's app info", e);
             return;
@@ -553,7 +552,8 @@
             headerTitleText.setText(appLabel);
         }
         // Set up media rec card's tap action if applicable.
-        setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction());
+        setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
+                /* interactedSubcardRank */ -1);
         // Set up media rec card's accessibility label.
         recommendationCard.setContentDescription(
                 mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel));
@@ -567,7 +567,8 @@
         ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
         int mediaRecommendationNum = Math.min(mediaRecommendationList.size(),
                 MEDIA_RECOMMENDATION_MAX_NUM);
-        for (int itemIndex = 0, uiComponentIndex = 0;
+        int uiComponentIndex = 0;
+        for (int itemIndex = 0;
                 itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum;
                 itemIndex++) {
             SmartspaceAction recommendation = mediaRecommendationList.get(itemIndex);
@@ -582,7 +583,8 @@
 
             // Set up the media item's click listener if applicable.
             ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex);
-            setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation);
+            setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation,
+                    uiComponentIndex);
 
             // Set up the accessibility label for the media item.
             String artistName = recommendation.getExtras()
@@ -614,10 +616,10 @@
                     mediaCoverItemsResIds.get(uiComponentIndex), true);
             setVisibleAndAlpha(expandedSet,
                     mediaCoverContainersResIds.get(uiComponentIndex), true);
-
             uiComponentIndex++;
         }
 
+        mSmartspaceMediaItemsCount = uiComponentIndex;
         // Set up long press to show guts setting panel.
         mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
             logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
@@ -750,7 +752,8 @@
 
     private void setSmartspaceRecItemOnClickListener(
             @NonNull View view,
-            @NonNull SmartspaceAction action) {
+            @NonNull SmartspaceAction action,
+            int interactedSubcardRank) {
         if (view == null || action == null || action.getIntent() == null
                 || action.getIntent().getExtras() == null) {
             Log.e(TAG, "No tap action can be set up");
@@ -758,9 +761,10 @@
         }
 
         view.setOnClickListener(v -> {
-            // When media recommendation card is shown, it will always be the top card.
             logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
-                    /* isRecommendationCard */ true);
+                    /* isRecommendationCard */ true,
+                    interactedSubcardRank,
+                    getSmartspaceSubCardCardinality());
 
             if (shouldSmartspaceRecItemOpenInForeground(action)) {
                 // Request to unlock the device if the activity needs to be opened in foreground.
@@ -818,9 +822,28 @@
     }
 
     private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard) {
+        logSmartspaceCardReported(eventId, isRecommendationCard,
+                /* interactedSubcardRank */ 0,
+                /* interactedSubcardCardinality */ 0);
+    }
+
+    private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard,
+            int interactedSubcardRank, int interactedSubcardCardinality) {
         mMediaCarouselController.logSmartspaceCardReported(eventId,
                 mInstanceId,
+                mUid,
                 isRecommendationCard,
-                getSurfaceForSmartspaceLogging());
+                getSurfaceForSmartspaceLogging(),
+                interactedSubcardRank,
+                interactedSubcardCardinality);
     }
-}
+
+    private int getSmartspaceSubCardCardinality() {
+        if (!mMediaCarouselController.getMediaCarouselScrollHandler().getQsExpanded()
+                && mSmartspaceMediaItemsCount > 3) {
+            return 3;
+        }
+
+        return mSmartspaceMediaItemsCount;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 89786ee..a617850 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -139,7 +139,7 @@
                                 + " with ducking", e);
                     }
                     player.start();
-                    if (DEBUG) { Log.d(mTag, "player.start"); }
+                    if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); }
                 } catch (Exception e) {
                     if (player != null) {
                         player.release();
@@ -155,7 +155,13 @@
                     mPlayer = player;
                 }
                 if (mp != null) {
-                    if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
+                    if (DEBUG) {
+                        Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+                    }
+                    mp.pause();
+                    try {
+                        Thread.sleep(100);
+                    } catch (InterruptedException ie) { }
                     mp.release();
                 }
                 this.notify();
@@ -244,6 +250,10 @@
                         try {
                             mp.stop();
                         } catch (Exception e) { }
+                        if (DEBUG) {
+                            Log.i(mTag, "About to release MediaPlayer piid:"
+                                    + mp.getPlayerIId() + " due to notif cancelled");
+                        }
                         mp.release();
                         synchronized(mQueueAudioFocusLock) {
                             if (mAudioManagerWithAudioFocus != null) {
@@ -284,7 +294,7 @@
     public void onCompletion(MediaPlayer mp) {
         synchronized(mQueueAudioFocusLock) {
             if (mAudioManagerWithAudioFocus != null) {
-                if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus");
+                if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus");
                 mAudioManagerWithAudioFocus.abandonAudioFocus(null);
                 mAudioManagerWithAudioFocus = null;
             } else {
@@ -310,6 +320,10 @@
             }
         }
         if (mp != null) {
+            if (DEBUG) {
+                Log.i("NotificationPlayer", "About to release MediaPlayer piid:"
+                        + mp.getPlayerIId() + " due to onCompletion");
+            }
             mp.release();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 791f59d..35603b6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -43,7 +43,6 @@
     val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
     val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
     val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
-    val seamlessFallback = itemView.requireViewById<ImageView>(R.id.media_seamless_fallback)
 
     // Seek bar
     val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
@@ -124,7 +123,6 @@
                 R.id.header_title,
                 R.id.header_artist,
                 R.id.media_seamless,
-                R.id.media_seamless_fallback,
                 R.id.notification_media_progress_time,
                 R.id.media_progress_bar,
                 R.id.action0,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 5293c88..b2def7a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -466,7 +466,7 @@
     }
 
     boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
-        return !device.getFeatures().contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+        return !isActiveRemoteDevice(device);
     }
 
     private final MediaController.Callback mCb = new MediaController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4a67e94..7de0a12 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -422,6 +422,12 @@
             new Handler(Looper.getMainLooper())) {
         @Override
         public void onChange(boolean selfChange, Uri uri) {
+            // TODO(b/198002034): Content observers currently can still be called back after being
+            // unregistered, and in this case we can ignore the change if the nav bar has been
+            // destroyed already
+            if (mNavigationBarView == null) {
+                return;
+            }
             updateAssistantEntrypoints();
         }
     };
@@ -648,7 +654,7 @@
         if (mIsOnDefaultDisplay) {
             final RotationButtonController rotationButtonController =
                     mNavigationBarView.getRotationButtonController();
-            rotationButtonController.addRotationCallback(mRotationWatcher);
+            rotationButtonController.setRotationCallback(mRotationWatcher);
 
             // Reset user rotation pref to match that of the WindowManager if starting in locked
             // mode. This will automatically happen when switching from auto-rotate to locked mode.
@@ -687,6 +693,9 @@
 
     @Override
     public void onViewDetachedFromWindow(View v) {
+        final RotationButtonController rotationButtonController =
+                mNavigationBarView.getRotationButtonController();
+        rotationButtonController.setRotationCallback(null);
         mNavigationBarView.getBarTransitions().destroy();
         mNavigationBarView.getLightTransitionsController().destroy(mContext);
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 543004e..2e7ab6e 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. */
@@ -191,8 +191,8 @@
         mNavMode = mNavigationModeController.addListener(this);
         mNavigationModeController.addListener(this);
         mTaskbarDelegate = taskbarDelegate;
-        mTaskbarDelegate.setOverviewProxyService(overviewProxyService,
-                navigationBarA11yHelper, mSysUiFlagsContainer);
+        mTaskbarDelegate.setOverviewProxyService(commandQueue, overviewProxyService,
+                navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer);
         mIsTablet = isTablet(mContext);
         mUserTracker = userTracker;
     }
@@ -251,17 +251,14 @@
 
     /** @return {@code true} if taskbar is enabled, false otherwise */
     private boolean initializeTaskbarIfNecessary() {
-        boolean isShowingTaskbar = mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON;
-        if (isShowingTaskbar) {
-            // Remove navigation bar when taskbar is showing, currently only for 3 button mode
+        if (mIsTablet) {
+            // Remove navigation bar when taskbar is showing
             removeNavigationBar(mContext.getDisplayId());
-            mCommandQueue.addCallback(mTaskbarDelegate);
             mTaskbarDelegate.init(mContext.getDisplayId());
         } else {
-            mCommandQueue.removeCallback(mTaskbarDelegate);
             mTaskbarDelegate.destroy();
         }
-        return isShowingTaskbar;
+        return mIsTablet;
     }
 
     @Override
@@ -332,7 +329,7 @@
             return;
         }
 
-        if (mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON) {
+        if (mIsTablet) {
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 2d36de3..2de4026 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -19,9 +19,7 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
@@ -79,9 +77,9 @@
 import com.android.systemui.navigationbar.buttons.RotationContextButton;
 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.navigationbar.gestural.FloatingRotationButton;
-import com.android.systemui.navigationbar.gestural.RegionSamplingHelper;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.SysUiStatsLog;
@@ -281,7 +279,7 @@
             new RotationButtonUpdatesCallback() {
                 @Override
                 public void onVisibilityChanged(boolean visible) {
-                    if (visible) {
+                    if (visible && mAutoHideController != null) {
                         // If the button will actually become visible and the navbar is about
                         // to hide, tell the statusbar to keep it around for longer
                         mAutoHideController.touchAutoHide();
@@ -841,7 +839,6 @@
 
     public void onStatusBarPanelStateChanged() {
         updateSlippery();
-        updatePanelSystemUiStateFlags();
     }
 
     public void updateDisabledSystemUiStateFlags() {
@@ -858,21 +855,12 @@
                 .commitUpdate(displayId);
     }
 
-    public void updatePanelSystemUiStateFlags() {
-        int displayId = mContext.getDisplayId();
+    private void updatePanelSystemUiStateFlags() {
         if (SysUiState.DEBUG) {
             Log.d(TAG, "Updating panel sysui state flags: panelView=" + mPanelView);
         }
         if (mPanelView != null) {
-            if (SysUiState.DEBUG) {
-                Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
-                        + mPanelView.isFullyExpanded() + " inQs=" + mPanelView.isInSettings());
-            }
-            mSysUiFlagContainer.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
-                    mPanelView.isFullyExpanded() && !mPanelView.isInSettings())
-                    .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
-                            mPanelView.isInSettings())
-                    .commitUpdate(displayId);
+            mPanelView.updateSystemUiStateFlags();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index 196625b..0f5c03a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -183,7 +183,7 @@
         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
     }
 
-    void addRotationCallback(Consumer<Integer> watcher) {
+    void setRotationCallback(Consumer<Integer> watcher) {
         mRotWatcherListener = watcher;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index fe24ecd..3167070 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -18,18 +18,32 @@
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
+import android.app.StatusBarManager;
+import android.app.StatusBarManager.WindowVisibleState;
+import android.content.Context;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.view.InsetsVisibilities;
+import android.view.View;
+import android.view.WindowInsetsController.Behavior;
 
 import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.Dependency;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.statusbar.CommandQueue;
@@ -38,33 +52,55 @@
 import javax.inject.Singleton;
 
 @Singleton
-public class TaskbarDelegate implements CommandQueue.Callbacks {
+public class TaskbarDelegate implements CommandQueue.Callbacks,
+        OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener {
 
+    private final EdgeBackGestureHandler mEdgeBackGestureHandler;
+
+    private CommandQueue mCommandQueue;
     private OverviewProxyService mOverviewProxyService;
     private NavigationBarA11yHelper mNavigationBarA11yHelper;
+    private NavigationModeController mNavigationModeController;
     private SysUiState mSysUiState;
     private int mDisplayId;
     private int mNavigationIconHints;
     private final NavigationBarA11yHelper.NavA11yEventListener mNavA11yEventListener =
             this::updateSysuiFlags;
-    @Inject
-    public TaskbarDelegate() { /* no-op */ }
+    private int mDisabledFlags;
+    private @WindowVisibleState int mTaskBarWindowState = WINDOW_STATE_SHOWING;
+    private @Behavior int mBehavior;
 
-    public void setOverviewProxyService(OverviewProxyService overviewProxyService,
+    @Inject
+    public TaskbarDelegate(Context context) {
+        mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class)
+                .create(context);
+    }
+
+    public void setOverviewProxyService(CommandQueue commandQueue,
+            OverviewProxyService overviewProxyService,
             NavigationBarA11yHelper navigationBarA11yHelper,
+            NavigationModeController navigationModeController,
             SysUiState sysUiState) {
         // TODO: adding this in the ctor results in a dagger dependency cycle :(
+        mCommandQueue = commandQueue;
         mOverviewProxyService = overviewProxyService;
         mNavigationBarA11yHelper = navigationBarA11yHelper;
+        mNavigationModeController = navigationModeController;
         mSysUiState = sysUiState;
     }
 
     public void destroy() {
+        mCommandQueue.removeCallback(this);
+        mOverviewProxyService.removeCallback(this);
+        mNavigationModeController.removeListener(this);
         mNavigationBarA11yHelper.removeA11yEventListener(mNavA11yEventListener);
     }
 
     public void init(int displayId) {
         mDisplayId = displayId;
+        mCommandQueue.addCallback(this);
+        mOverviewProxyService.addCallback(this);
+        mNavigationModeController.addListener(this);
         mNavigationBarA11yHelper.registerA11yEventListener(mNavA11yEventListener);
         // Set initial state for any listeners
         updateSysuiFlags();
@@ -81,6 +117,15 @@
                         (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
                 .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING,
                         (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0)
+                .setFlag(SYSUI_STATE_OVERVIEW_DISABLED,
+                        (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0)
+                .setFlag(SYSUI_STATE_HOME_DISABLED,
+                        (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0)
+                .setFlag(SYSUI_STATE_BACK_DISABLED,
+                        (mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
+                .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isWindowVisible())
+                .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
+                        allowSystemGestureIgnoringBarVisibility())
                 .commitUpdate(mDisplayId);
     }
 
@@ -97,12 +142,24 @@
     }
 
     @Override
+    public void setWindowState(int displayId, int window, int state) {
+        if (displayId == mDisplayId
+                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
+                && mTaskBarWindowState != state) {
+            mTaskBarWindowState = state;
+            updateSysuiFlags();
+        }
+    }
+
+    @Override
     public void onRotationProposal(int rotation, boolean isValid) {
         mOverviewProxyService.onRotationProposal(rotation, isValid);
     }
 
     @Override
     public void disable(int displayId, int state1, int state2, boolean animate) {
+        mDisabledFlags = state1;
+        updateSysuiFlags();
         mOverviewProxyService.disable(displayId, state1, state2, animate);
     }
 
@@ -111,5 +168,31 @@
             AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
             InsetsVisibilities requestedVisibilities, String packageName) {
         mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
+        if (mBehavior != behavior) {
+            mBehavior = behavior;
+            updateSysuiFlags();
+        }
+    }
+
+    @Override
+    public void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
+        if (visible) {
+            mEdgeBackGestureHandler.onNavBarAttached();
+        } else {
+            mEdgeBackGestureHandler.onNavBarDetached();
+        }
+    }
+
+    @Override
+    public void onNavigationModeChanged(int mode) {
+        mEdgeBackGestureHandler.onNavigationModeChanged(mode);
+    }
+
+    private boolean isWindowVisible() {
+        return mTaskBarWindowState == WINDOW_STATE_SHOWING;
+    }
+
+    private boolean allowSystemGestureIgnoringBarVisibility() {
+        return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 2bf4bf4..bf1a98f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -106,7 +106,7 @@
     static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
 
     private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
-            SystemProperties.getBoolean("persist.debug.per_window_input_rotation", true);
+            SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
 
     private ISystemGestureExclusionListener mGestureExclusionListener =
             new ISystemGestureExclusionListener.Stub() {
@@ -384,7 +384,7 @@
     private void onNavigationSettingsChanged() {
         boolean wasBackAllowed = isHandlingGestures();
         updateCurrentUserResources();
-        if (wasBackAllowed != isHandlingGestures()) {
+        if (mStateChangeCallback != null && wasBackAllowed != isHandlingGestures()) {
             mStateChangeCallback.run();
         }
     }
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 ea04cef..8d1dfc8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -55,6 +55,7 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.NavigationEdgeBackPlugin;
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 import com.android.systemui.statusbar.VibratorHelper;
 
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
index ad1e21d..0b565ea 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
@@ -17,25 +17,27 @@
 import android.util.ArrayMap;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.PluginDependency.DependencyProvider;
 import com.android.systemui.shared.plugins.PluginManager;
 
 import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
 
 /**
  */
-@SysUISingleton
+@Singleton
 public class PluginDependencyProvider extends DependencyProvider {
 
     private final ArrayMap<Class<?>, Object> mDependencies = new ArrayMap<>();
-    private final PluginManager mManager;
+    private final Lazy<PluginManager> mManagerLazy;
 
     /**
      */
     @Inject
-    public PluginDependencyProvider(PluginManager manager) {
-        mManager = manager;
+    public PluginDependencyProvider(Lazy<PluginManager> managerLazy) {
+        mManagerLazy = managerLazy;
         PluginDependency.sProvider = this;
     }
 
@@ -51,7 +53,7 @@
 
     @Override
     <T> T get(Plugin p, Class<T> cls) {
-        if (!mManager.dependsOn(p, cls)) {
+        if (!mManagerLazy.get().dependsOn(p, cls)) {
             throw new IllegalArgumentException(p.getClass() + " does not depend on " + cls);
         }
         synchronized (mDependencies) {
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
index 6337415..40f59744 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
@@ -22,16 +22,22 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.shared.plugins.PluginEnabler;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** */
+@Singleton
 public class PluginEnablerImpl implements PluginEnabler {
     private static final String CRASH_DISABLED_PLUGINS_PREF_FILE = "auto_disabled_plugins_prefs";
 
-    private PackageManager mPm;
+    private final PackageManager mPm;
     private final SharedPreferences mAutoDisabledPrefs;
 
     public PluginEnablerImpl(Context context) {
         this(context, context.getPackageManager());
     }
 
+    @Inject
     @VisibleForTesting public PluginEnablerImpl(Context context, PackageManager pm) {
         mAutoDisabledPrefs = context.getSharedPreferences(
                 CRASH_DISABLED_PLUGINS_PREF_FILE, Context.MODE_PRIVATE);
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
index 7f01d6f..654d000 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
@@ -15,16 +15,17 @@
 package com.android.systemui.plugins;
 
 import android.content.Context;
-import android.os.Build;
-import android.os.Looper;
 import android.util.Log;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.shared.plugins.PluginEnabler;
 import com.android.systemui.shared.plugins.PluginInitializer;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** */
+@Singleton
 public class PluginInitializerImpl implements PluginInitializer {
 
     /**
@@ -33,44 +34,24 @@
     private static final boolean WTFS_SHOULD_CRASH = false;
     private boolean mWtfsSet;
 
-    @Override
-    public Looper getBgLooper() {
-        return Dependency.get(Dependency.BG_LOOPER);
+    @Inject
+    public PluginInitializerImpl(PluginDependencyProvider  dependencyProvider) {
+        dependencyProvider.allowPluginDependency(ActivityStarter.class);
     }
 
     @Override
-    public void onPluginManagerInit() {
-        // Plugin dependencies that don't have another good home can go here, but
-        // dependencies that have better places to init can happen elsewhere.
-        Dependency.get(PluginDependencyProvider.class)
-                .allowPluginDependency(ActivityStarter.class);
-    }
-
-    @Override
-    public String[] getWhitelistedPlugins(Context context) {
+    public String[] getPrivilegedPlugins(Context context) {
         return context.getResources().getStringArray(R.array.config_pluginWhitelist);
     }
 
-    public PluginEnabler getPluginEnabler(Context context) {
-        return new PluginEnablerImpl(context);
-    }
 
     @Override
     public void handleWtfs() {
         if (WTFS_SHOULD_CRASH && !mWtfsSet) {
             mWtfsSet = true;
-            Log.setWtfHandler(new Log.TerribleFailureHandler() {
-                @Override
-                public void onTerribleFailure(String tag, Log.TerribleFailure what,
-                        boolean system) {
-                    throw new PluginManagerImpl.CrashWhilePluginActiveException(what);
-                }
+            Log.setWtfHandler((tag, what, system) -> {
+                throw new PluginManagerImpl.CrashWhilePluginActiveException(what);
             });
         }
     }
-
-    @Override
-    public boolean isDebuggable() {
-        return Build.IS_DEBUGGABLE;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
new file mode 100644
index 0000000..1ea9b3c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
@@ -0,0 +1,116 @@
+/*
+ * 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 static com.android.systemui.util.concurrency.GlobalConcurrencyModule.PRE_HANDLER;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shared.plugins.PluginEnabler;
+import com.android.systemui.shared.plugins.PluginInitializer;
+import com.android.systemui.shared.plugins.PluginInstanceManager;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.shared.plugins.PluginManagerImpl;
+import com.android.systemui.shared.plugins.PluginPrefs;
+import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
+import com.android.systemui.util.concurrency.ThreadFactory;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.Executor;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module for code related to plugins.
+ *
+ * Covers code both in com.android.systemui.plugins and code in
+ * com.android.systemui.shared.plugins.
+ */
+@Module(includes = {GlobalConcurrencyModule.class})
+public abstract class PluginsModule {
+    public static final String PLUGIN_THREAD = "plugin_thread";
+    public static final String PLUGIN_DEBUG = "plugin_debug";
+    public static final String PLUGIN_PRIVILEGED = "plugin_privileged";
+
+    @Provides
+    @Named(PLUGIN_DEBUG)
+    static boolean providesPluginDebug() {
+        return Build.IS_DEBUGGABLE;
+    }
+
+    @Binds
+    abstract PluginEnabler bindsPluginEnablerImpl(PluginEnablerImpl impl);
+
+    @Binds
+    abstract PluginInitializer bindsPluginInitializerImpl(PluginInitializerImpl impl);
+
+    @Provides
+    @Singleton
+    static PluginInstanceManager.Factory providePluginInstanceManagerFactory(Context context,
+            PackageManager packageManager, @Main Executor mainExecutor,
+            @Named(PLUGIN_THREAD) Executor pluginExecutor, PluginInitializer initializer,
+            NotificationManager notificationManager, PluginEnabler pluginEnabler,
+            @Named(PLUGIN_PRIVILEGED) List<String> privilegedPlugins) {
+        return new PluginInstanceManager.Factory(
+                context, packageManager, mainExecutor, pluginExecutor, initializer,
+                notificationManager, pluginEnabler, privilegedPlugins);
+    }
+
+    @Provides
+    @Singleton
+    @Named(PLUGIN_THREAD)
+    static Executor providesPluginExecutor(ThreadFactory threadFactory) {
+        return threadFactory.buildExecutorOnNewThread("plugin");
+    }
+
+    @Provides
+    static PluginManager providesPluginManager(
+            Context context,
+            PluginInstanceManager.Factory instanceManagerFactory,
+            @Named(PLUGIN_DEBUG) boolean debug,
+            @Named(PRE_HANDLER)
+                    Optional<Thread.UncaughtExceptionHandler> uncaughtExceptionHandlerOptional,
+            PluginEnabler pluginEnabler,
+            PluginPrefs pluginPrefs,
+            @Named(PLUGIN_PRIVILEGED) List<String> privilegedPlugins) {
+        return new PluginManagerImpl(context, instanceManagerFactory, debug,
+                uncaughtExceptionHandlerOptional, pluginEnabler, pluginPrefs,
+                privilegedPlugins);
+    }
+
+    @Provides
+    static PluginPrefs providesPluginPrefs(Context context) {
+        return new PluginPrefs(context);
+    }
+
+    @Provides
+    @Named(PLUGIN_PRIVILEGED)
+    static List<String> providesPrivilegedPlugins(PluginInitializer initializer, Context context) {
+        return Arrays.asList(initializer.getPrivilegedPlugins(context));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
index d94cd28..8750976 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
@@ -24,13 +24,17 @@
 import android.annotation.IntDef;
 import android.annotation.UiThread;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.util.Log;
 import android.view.Gravity;
+import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -98,6 +102,10 @@
     private final Context mContext;
     private final PrivacyItemController mPrivacyItemController;
 
+    private final IWindowManager mIWindowManager;
+    private final Rect[] mBounds = new Rect[4];
+    private boolean mIsRtl;
+
     private ViewGroup mIndicatorView;
     private boolean mViewAndWindowAdded;
     private ObjectAnimator mAnimator;
@@ -124,17 +132,23 @@
     private int mState = STATE_NOT_SHOWN;
 
     @Inject
-    public TvOngoingPrivacyChip(Context context, PrivacyItemController privacyItemController) {
+    public TvOngoingPrivacyChip(Context context, PrivacyItemController privacyItemController,
+            IWindowManager iWindowManager) {
         super(context);
         if (DEBUG) Log.d(TAG, "Privacy chip running");
         mContext = context;
         mPrivacyItemController = privacyItemController;
+        mIWindowManager = iWindowManager;
 
         Resources res = mContext.getResources();
         mIconMarginStart = Math.round(
                 res.getDimension(R.dimen.privacy_chip_icon_margin_in_between));
         mIconSize = res.getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
 
+        mIsRtl = mContext.getResources().getConfiguration().getLayoutDirection()
+                == View.LAYOUT_DIRECTION_RTL;
+        updateStaticPrivacyIndicatorBounds();
+
         mAnimationDurationMs = res.getInteger(R.integer.privacy_chip_animation_millis);
 
         mMicCameraIndicatorFlagEnabled = privacyItemController.getMicCameraAvailable();
@@ -147,6 +161,24 @@
     }
 
     @Override
+    public void onConfigurationChanged(Configuration config) {
+        boolean updatedRtl = config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        if (mIsRtl == updatedRtl) {
+            return;
+        }
+        mIsRtl = updatedRtl;
+
+        updateStaticPrivacyIndicatorBounds();
+
+        // Update privacy chip location.
+        if (mState == STATE_NOT_SHOWN || mIndicatorView == null) {
+            return;
+        }
+        fadeOutIndicator();
+        createAndShowIndicator();
+    }
+
+    @Override
     public void start() {
         mPrivacyItemController.addCallback(this);
     }
@@ -181,6 +213,32 @@
         updateChip();
     }
 
+    private void updateStaticPrivacyIndicatorBounds() {
+        Resources res = mContext.getResources();
+        int mMaxExpandedWidth = res.getDimensionPixelSize(R.dimen.privacy_chip_max_width);
+        int mMaxExpandedHeight = res.getDimensionPixelSize(R.dimen.privacy_chip_height);
+        int mChipMarginTotal = 2 * res.getDimensionPixelSize(R.dimen.privacy_chip_margin);
+
+        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+        Rect screenBounds = windowManager.getCurrentWindowMetrics().getBounds();
+        mBounds[0] = new Rect(
+                mIsRtl ? screenBounds.left
+                        : screenBounds.right - mChipMarginTotal - mMaxExpandedWidth,
+                screenBounds.top,
+                mIsRtl ? screenBounds.left + mChipMarginTotal + mMaxExpandedWidth
+                        : screenBounds.right,
+                screenBounds.top + mChipMarginTotal + mMaxExpandedHeight
+        );
+
+        if (DEBUG) Log.v(TAG, "privacy indicator bounds: " + mBounds[0].toShortString());
+
+        try {
+            mIWindowManager.updateStaticPrivacyIndicatorBounds(mContext.getDisplayId(), mBounds);
+        } catch (RemoteException e) {
+            Log.w(TAG, "could not update privacy indicator bounds");
+        }
+    }
+
     private void updateChip() {
         if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
 
@@ -316,13 +374,9 @@
                             }
                         });
 
-        final boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
-                == View.LAYOUT_DIRECTION_RTL;
-        if (DEBUG) Log.d(TAG, "is RTL: " + isRtl);
-
         mChipDrawable = new PrivacyChipDrawable(mContext);
         mChipDrawable.setListener(this);
-        mChipDrawable.setRtl(isRtl);
+        mChipDrawable.setRtl(mIsRtl);
         ImageView chipBackground = mIndicatorView.findViewById(R.id.chip_drawable);
         if (chipBackground != null) {
             chipBackground.setImageDrawable(mChipDrawable);
@@ -332,17 +386,21 @@
         mIconsContainer.setAlpha(0f);
         updateIcons();
 
+        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+        windowManager.addView(mIndicatorView, getWindowLayoutParams());
+    }
+
+    private WindowManager.LayoutParams getWindowLayoutParams() {
         final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                 WRAP_CONTENT,
                 WRAP_CONTENT,
                 WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                 PixelFormat.TRANSLUCENT);
-        layoutParams.gravity = Gravity.TOP | (isRtl ? Gravity.LEFT : Gravity.RIGHT);
+        layoutParams.gravity = Gravity.TOP | (mIsRtl ? Gravity.LEFT : Gravity.RIGHT);
         layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
         layoutParams.packageName = mContext.getPackageName();
-        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
-        windowManager.addView(mIndicatorView, layoutParams);
+        return layoutParams;
     }
 
     private void updateIcons() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
deleted file mode 100644
index 38b20ee..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.qs;
-
-import static com.android.systemui.statusbar.phone.AutoTileManager.HOTSPOT;
-import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
-import static com.android.systemui.statusbar.phone.AutoTileManager.NIGHT;
-import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
-import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings.Secure;
-import android.text.TextUtils;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
-import com.android.systemui.util.UserAwareController;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-import javax.inject.Inject;
-
-public class AutoAddTracker implements UserAwareController {
-
-    private static final String[][] CONVERT_PREFS = {
-            {Key.QS_HOTSPOT_ADDED, HOTSPOT},
-            {Key.QS_DATA_SAVER_ADDED, SAVER},
-            {Key.QS_INVERT_COLORS_ADDED, INVERSION},
-            {Key.QS_WORK_ADDED, WORK},
-            {Key.QS_NIGHTDISPLAY_ADDED, NIGHT},
-    };
-
-    private final ArraySet<String> mAutoAdded;
-    private final Context mContext;
-    private int mUserId;
-
-    public AutoAddTracker(Context context, int userId) {
-        mContext = context;
-        mUserId = userId;
-        mAutoAdded = new ArraySet<>(getAdded());
-    }
-
-    /**
-     * Init method must be called after construction to start listening
-     */
-    public void initialize() {
-        // TODO: remove migration code and shared preferences keys after P release
-        if (mUserId == UserHandle.USER_SYSTEM) {
-            for (String[] convertPref : CONVERT_PREFS) {
-                if (Prefs.getBoolean(mContext, convertPref[0], false)) {
-                    setTileAdded(convertPref[1]);
-                    Prefs.remove(mContext, convertPref[0]);
-                }
-            }
-        }
-        mContext.getContentResolver().registerContentObserver(
-                Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver,
-                UserHandle.USER_ALL);
-    }
-
-    @Override
-    public void changeUser(UserHandle newUser) {
-        if (newUser.getIdentifier() == mUserId) {
-            return;
-        }
-        mUserId = newUser.getIdentifier();
-        mAutoAdded.clear();
-        mAutoAdded.addAll(getAdded());
-    }
-
-    @Override
-    public int getCurrentUserId() {
-        return mUserId;
-    }
-
-    public boolean isAdded(String tile) {
-        return mAutoAdded.contains(tile);
-    }
-
-    public void setTileAdded(String tile) {
-        if (mAutoAdded.add(tile)) {
-            saveTiles();
-        }
-    }
-
-    public void setTileRemoved(String tile) {
-        if (mAutoAdded.remove(tile)) {
-            saveTiles();
-        }
-    }
-
-    public void destroy() {
-        mContext.getContentResolver().unregisterContentObserver(mObserver);
-    }
-
-    private void saveTiles() {
-        Secure.putStringForUser(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES,
-                TextUtils.join(",", mAutoAdded), mUserId);
-    }
-
-    private Collection<String> getAdded() {
-        String current = Secure.getStringForUser(mContext.getContentResolver(),
-                Secure.QS_AUTO_ADDED_TILES, mUserId);
-        if (current == null) {
-            return Collections.emptyList();
-        }
-        return Arrays.asList(current.split(","));
-    }
-
-    @VisibleForTesting
-    protected final ContentObserver mObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            mAutoAdded.clear();
-            mAutoAdded.addAll(getAdded());
-        }
-    };
-
-    public static class Builder {
-        private final Context mContext;
-        private int mUserId;
-
-        @Inject
-        public Builder(Context context) {
-            mContext = context;
-        }
-
-        public Builder setUserId(int userId) {
-            mUserId = userId;
-            return this;
-        }
-
-        public AutoAddTracker build() {
-            return new AutoAddTracker(mContext, mUserId);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
new file mode 100644
index 0000000..7ffa9d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
@@ -0,0 +1,285 @@
+/*
+ * 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.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.database.ContentObserver
+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.Log
+import androidx.annotation.GuardedBy
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.UserAwareController
+import com.android.systemui.util.settings.SecureSettings
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+private const val TAG = "AutoAddTracker"
+
+/**
+ * Class to track tiles that have been auto-added
+ *
+ * The list is backed by [Settings.Secure.QS_AUTO_ADDED_TILES].
+ *
+ * It also handles restore gracefully.
+ */
+class AutoAddTracker @VisibleForTesting constructor(
+    private val secureSettings: SecureSettings,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val qsHost: QSHost,
+    private val dumpManager: DumpManager,
+    private val mainHandler: Handler?,
+    private val backgroundExecutor: Executor,
+    private var userId: Int
+) : UserAwareController, Dumpable {
+
+    companion object {
+        private val FILTER = IntentFilter(Intent.ACTION_SETTING_RESTORED)
+    }
+
+    @GuardedBy("autoAdded")
+    private val autoAdded = ArraySet<String>()
+    private var restoredTiles: Set<String>? = null
+
+    override val currentUserId: Int
+        get() = userId
+
+    private val contentObserver = object : ContentObserver(mainHandler) {
+        override fun onChange(
+            selfChange: Boolean,
+            uris: Collection<Uri>,
+            flags: Int,
+            _userId: Int
+        ) {
+            if (_userId != userId) {
+                // Ignore changes outside of our user. We'll load the correct value on user change
+                return
+            }
+            loadTiles()
+        }
+    }
+
+    private val restoreReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            if (intent.action != Intent.ACTION_SETTING_RESTORED) return
+            processRestoreIntent(intent)
+        }
+    }
+
+    private fun processRestoreIntent(intent: Intent) {
+        when (intent.getStringExtra(Intent.EXTRA_SETTING_NAME)) {
+            Settings.Secure.QS_TILES -> {
+                restoredTiles = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)
+                        ?.split(",")
+                        ?.toSet()
+                        ?: run {
+                            Log.w(TAG, "Null restored tiles for user $userId")
+                            emptySet()
+                        }
+            }
+            Settings.Secure.QS_AUTO_ADDED_TILES -> {
+                restoredTiles?.let { tiles ->
+                    val restoredAutoAdded = intent
+                            .getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)
+                            ?.split(",")
+                            ?: emptyList()
+                    val autoAddedBeforeRestore = intent
+                            .getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE)
+                            ?.split(",")
+                            ?: emptyList()
+
+                    val tilesToRemove = restoredAutoAdded.filter { it !in tiles }
+                    if (tilesToRemove.isNotEmpty()) {
+                        qsHost.removeTiles(tilesToRemove)
+                    }
+                    val tiles = synchronized(autoAdded) {
+                        autoAdded.clear()
+                        autoAdded.addAll(restoredAutoAdded + autoAddedBeforeRestore)
+                        getTilesFromListLocked()
+                    }
+                    saveTiles(tiles)
+                } ?: run {
+                    Log.w(TAG, "${Settings.Secure.QS_AUTO_ADDED_TILES} restored before " +
+                            "${Settings.Secure.QS_TILES} for user $userId")
+                }
+            }
+            else -> {} // Do nothing for other Settings
+        }
+    }
+
+    /**
+     * Init method must be called after construction to start listening
+     */
+    fun initialize() {
+        dumpManager.registerDumpable(TAG, this)
+        loadTiles()
+        secureSettings.registerContentObserverForUser(
+                secureSettings.getUriFor(Settings.Secure.QS_AUTO_ADDED_TILES),
+                contentObserver,
+                UserHandle.USER_ALL
+        )
+        registerBroadcastReceiver()
+    }
+
+    /**
+     * Unregister listeners, receivers and observers
+     */
+    fun destroy() {
+        dumpManager.unregisterDumpable(TAG)
+        secureSettings.unregisterContentObserver(contentObserver)
+        unregisterBroadcastReceiver()
+    }
+
+    private fun registerBroadcastReceiver() {
+        broadcastDispatcher.registerReceiver(
+                restoreReceiver,
+                FILTER,
+                backgroundExecutor,
+                UserHandle.of(userId)
+        )
+    }
+
+    private fun unregisterBroadcastReceiver() {
+        broadcastDispatcher.unregisterReceiver(restoreReceiver)
+    }
+
+    override fun changeUser(newUser: UserHandle) {
+        if (newUser.identifier == userId) return
+        unregisterBroadcastReceiver()
+        userId = newUser.identifier
+        restoredTiles = null
+        loadTiles()
+        registerBroadcastReceiver()
+    }
+
+    /**
+     * Returns `true` if the tile has been auto-added before
+     */
+    fun isAdded(tile: String): Boolean {
+        return synchronized(autoAdded) {
+            tile in autoAdded
+        }
+    }
+
+    /**
+     * Sets a tile as auto-added.
+     *
+     * From here on, [isAdded] will return true for that tile.
+     */
+    fun setTileAdded(tile: String) {
+        val tiles = synchronized(autoAdded) {
+                if (autoAdded.add(tile)) {
+                    getTilesFromListLocked()
+                } else {
+                    null
+                }
+            }
+        tiles?.let { saveTiles(it) }
+    }
+
+    /**
+     * Removes a tile from the list of auto-added.
+     *
+     * This allows for this tile to be auto-added again in the future.
+     */
+    fun setTileRemoved(tile: String) {
+        val tiles = synchronized(autoAdded) {
+            if (autoAdded.remove(tile)) {
+                getTilesFromListLocked()
+            } else {
+                null
+            }
+        }
+        tiles?.let { saveTiles(it) }
+    }
+
+    private fun getTilesFromListLocked(): String {
+        return TextUtils.join(",", autoAdded)
+    }
+
+    private fun saveTiles(tiles: String) {
+        secureSettings.putStringForUser(
+                Settings.Secure.QS_AUTO_ADDED_TILES,
+                tiles,
+                /* tag */ null,
+                /* makeDefault */ false,
+                userId,
+                /* overrideableByRestore */ true
+        )
+    }
+
+    private fun loadTiles() {
+        synchronized(autoAdded) {
+            autoAdded.clear()
+            autoAdded.addAll(getAdded())
+        }
+    }
+
+    private fun getAdded(): Collection<String> {
+        val current = secureSettings.getStringForUser(Settings.Secure.QS_AUTO_ADDED_TILES, userId)
+        return current?.split(",") ?: emptySet()
+    }
+
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("Current user: $userId")
+        pw.println("Added tiles: $autoAdded")
+    }
+
+    @SysUISingleton
+    class Builder @Inject constructor(
+        private val secureSettings: SecureSettings,
+        private val broadcastDispatcher: BroadcastDispatcher,
+        private val qsHost: QSHost,
+        private val dumpManager: DumpManager,
+        @Main private val handler: Handler,
+        @Background private val executor: Executor
+    ) {
+        private var userId: Int = 0
+
+        fun setUserId(_userId: Int): Builder {
+            userId = _userId
+            return this
+        }
+
+        fun build(): AutoAddTracker {
+            return AutoAddTracker(
+                    secureSettings,
+                    broadcastDispatcher,
+                    qsHost,
+                    dumpManager,
+                    handler,
+                    executor,
+                    userId
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
new file mode 100644
index 0000000..4f87cad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -0,0 +1,225 @@
+/*
+ * 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.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.FooterActionsController.ExpansionState.COLLAPSED
+import com.android.systemui.qs.FooterActionsController.ExpansionState.EXPANDED
+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
+
+/**
+ * Manages [FooterActionsView] behaviour, both when it's placed in QS or QQS (split shade).
+ * Main difference between QS and QQS behaviour is condition when buttons should be visible,
+ * determined by [buttonsVisibleState]
+ */
+class FooterActionsController @Inject constructor(
+    view: FooterActionsView,
+    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,
+    private val buttonsVisibleState: ExpansionState
+) : ViewController<FooterActionsView>(view) {
+
+    enum class ExpansionState { COLLAPSED, EXPANDED }
+
+    private var listening: Boolean = false
+
+    var expanded = false
+        set(value) {
+            if (field != value) {
+                field = value
+                updateView()
+            }
+        }
+
+    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 (!buttonsVisible() || 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)
+        }
+    }
+
+    private fun buttonsVisible(): Boolean {
+        return when (buttonsVisibleState) {
+            EXPANDED -> expanded
+            COLLAPSED -> !expanded
+        }
+    }
+
+    override fun onInit() {
+        multiUserSwitchController.init()
+    }
+
+    fun hideFooter() {
+        mView.visibility = View.GONE
+    }
+
+    fun showFooter() {
+        mView.visibility = View.VISIBLE
+        updateView()
+    }
+
+    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) }
+        })
+
+        updateView()
+    }
+
+    private fun updateView() {
+        mView.updateEverything(buttonsVisible(), 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(buttonsVisible(), 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()
+    }
+
+    fun refreshVisibility(shouldBeVisible: Boolean) {
+        if (shouldBeVisible) {
+            showFooter()
+        } else {
+            hideFooter()
+        }
+    }
+
+    private fun isTunerEnabled() = tunerService.isTunerEnabled
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
new file mode 100644
index 0000000..fcfa72a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.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.qs
+
+import android.os.UserManager
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.globalactions.GlobalActionsDialogLite
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.FooterActionsController.ExpansionState
+import com.android.systemui.qs.dagger.QSFlagsModule
+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 javax.inject.Inject
+import javax.inject.Named
+
+class FooterActionsControllerBuilder @Inject constructor(
+    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(QSFlagsModule.PM_LITE_ENABLED) private val showPMLiteButton: Boolean
+) {
+    private lateinit var view: FooterActionsView
+    private lateinit var buttonsVisibleState: ExpansionState
+
+    fun withView(view: FooterActionsView): FooterActionsControllerBuilder {
+        this.view = view
+        return this
+    }
+
+    fun withButtonsVisibleWhen(state: ExpansionState): FooterActionsControllerBuilder {
+        buttonsVisibleState = state
+        return this
+    }
+
+    fun build(): FooterActionsController {
+        return FooterActionsController(view, qsPanelController, activityStarter, userManager,
+                userInfoController, multiUserSwitchController, deviceProvisionedController,
+                falsingManager, metricsLogger, tunerService, globalActionsDialog, uiEventLogger,
+                showPMLiteButton, buttonsVisibleState)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
new file mode 100644
index 0000000..941e54a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -0,0 +1,161 @@
+/*
+ * 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 FooterActionsView(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 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 setExpansion(headerExpansionFraction: Float) {
+        expansionAmount = headerExpansionFraction
+        if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction)
+    }
+
+    fun disable(
+        buttonsVisible: Boolean,
+        state2: Int,
+        isTunerEnabled: Boolean,
+        multiUserEnabled: Boolean
+    ) {
+        val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
+        if (disabled == qsDisabled) return
+        qsDisabled = disabled
+        updateEverything(buttonsVisible, isTunerEnabled, multiUserEnabled)
+    }
+
+    fun updateEverything(
+        buttonsVisible: Boolean,
+        isTunerEnabled: Boolean,
+        multiUserEnabled: Boolean
+    ) {
+        post {
+            updateVisibilities(buttonsVisible, 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(
+        buttonsVisible: Boolean,
+        isTunerEnabled: Boolean,
+        multiUserEnabled: Boolean
+    ) {
+        settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
+        tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
+        multiUserSwitch.visibility = if (buttonsVisible && multiUserEnabled) VISIBLE else GONE
+        val isDemo = UserManager.isDeviceInDemoMode(context)
+        settingsButton.visibility = if (isDemo || !buttonsVisible) INVISIBLE else VISIBLE
+    }
+
+    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/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/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
index 87c64c7..2f189be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -38,6 +38,7 @@
     private int mNumColumns = 3;
     private int mVerticalSpacing;
     private int mHorizontalSpacing;
+    private int mFixedChildWidth = -1;
 
     public PseudoGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -53,6 +54,8 @@
                 mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
             } else if (attr == R.styleable.PseudoGridView_horizontalSpacing) {
                 mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
+            } else if (attr == R.styleable.PseudoGridView_fixedChildWidth) {
+                mFixedChildWidth = a.getDimensionPixelSize(attr, -1);
             }
         }
 
@@ -65,8 +68,15 @@
             throw new UnsupportedOperationException("Needs a maximum width");
         }
         int width = MeasureSpec.getSize(widthMeasureSpec);
-
-        int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
+        int childWidth;
+        int necessarySpaceForChildWidth =
+                mFixedChildWidth * mNumColumns + mHorizontalSpacing * (mNumColumns - 1);
+        if (mFixedChildWidth != -1 && necessarySpaceForChildWidth <= width) {
+            childWidth = mFixedChildWidth;
+            width = mFixedChildWidth * mNumColumns + mHorizontalSpacing * (mNumColumns - 1);
+        } else {
+            childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
+        }
         int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
         int childHeightSpec = MeasureSpec.UNSPECIFIED;
         int totalHeight = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 4fcd46c..8659b8b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,6 +14,9 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FOOTER;
+
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.util.Log;
@@ -43,6 +46,7 @@
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /** */
 @QSScope
@@ -67,13 +71,15 @@
      * position to the normal QS panel. These views will only show once the animation is complete,
      * to prevent overlapping of semi transparent views
      */
-    private final ArrayList<View> mQuickQsViews = new ArrayList<>();
+    private final ArrayList<View> mAnimatedQsViews = new ArrayList<>();
     private final QuickQSPanel mQuickQsPanel;
     private final QSPanelController mQsPanelController;
     private final QuickQSPanelController mQuickQSPanelController;
     private final QuickStatusBarHeader mQuickStatusBarHeader;
     private final QSSecurityFooter mSecurityFooter;
     private final QS mQs;
+    private final View mQSFooterActions;
+    private final View mQQSFooterActions;
 
     private PagedTileLayout mPagedLayout;
 
@@ -88,6 +94,7 @@
     // This animates fading of SecurityFooter and media divider
     private TouchAnimator mAllPagesDelayedAnimator;
     private TouchAnimator mBrightnessAnimator;
+    private TouchAnimator mQQSFooterActionsAnimator;
     private HeightExpansionAnimator mQQSTileHeightAnimator;
     private HeightExpansionAnimator mOtherTilesExpandAnimator;
 
@@ -110,12 +117,16 @@
             QSPanelController qsPanelController,
             QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
             QSSecurityFooter securityFooter, @Main Executor executor, TunerService tunerService,
-            QSExpansionPathInterpolator qsExpansionPathInterpolator) {
+            QSExpansionPathInterpolator qsExpansionPathInterpolator,
+            @Named(QS_FOOTER) FooterActionsView qsFooterActionsView,
+            @Named(QQS_FOOTER) FooterActionsView qqsFooterActionsView) {
         mQs = qs;
         mQuickQsPanel = quickPanel;
         mQsPanelController = qsPanelController;
         mQuickQSPanelController = quickQSPanelController;
         mQuickStatusBarHeader = quickStatusBarHeader;
+        mQQSFooterActions = qqsFooterActionsView;
+        mQSFooterActions = qsFooterActionsView;
         mSecurityFooter = securityFooter;
         mHost = qsTileHost;
         mExecutor = executor;
@@ -262,7 +273,7 @@
 
         clearAnimationState();
         mAllViews.clear();
-        mQuickQsViews.clear();
+        mAnimatedQsViews.clear();
         mQQSTileHeightAnimator = null;
         mOtherTilesExpandAnimator = null;
 
@@ -360,7 +371,7 @@
 
                     firstPageBuilder.addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 1);
 
-                    mQuickQsViews.add(tileView);
+                    mAnimatedQsViews.add(tileView);
                     mAllViews.add(quickTileView);
                     mAllViews.add(quickTileView.getSecondaryLabel());
                 } else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -417,6 +428,13 @@
                     .addFloat(tileLayout, "alpha", 0, 1);
             mFirstPageDelayedAnimator = builder.build();
 
+            if (mQQSFooterActions.getVisibility() != View.GONE) {
+                // only when qqs footer is present (which means split shade mode) it needs to
+                // be animated
+                updateQQSFooterAnimation();
+            }
+
+
             // Fade in the security footer and the divider as we reach the final position
             builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
             builder.addFloat(mSecurityFooter.getView(), "alpha", 0, 1);
@@ -452,6 +470,20 @@
                 .addFloat(tileLayout, "alpha", 0, 1).build();
     }
 
+    private void updateQQSFooterAnimation() {
+        int[] qsPosition = new int[2];
+        int[] qqsPosition = new int[2];
+        View commonView = mQs.getView();
+        getRelativePositionInt(qsPosition, mQSFooterActions, commonView);
+        getRelativePositionInt(qqsPosition, mQQSFooterActions, commonView);
+        int translationY = (qsPosition[1] - qqsPosition[1])
+                - mQuickStatusBarHeader.getOffsetTranslation();
+        mQQSFooterActionsAnimator = new TouchAnimator.Builder()
+                .addFloat(mQQSFooterActions, "translationY", 0, translationY)
+                .build();
+        mAnimatedQsViews.add(mQSFooterActions);
+    }
+
     private boolean isIconInAnimatedRow(int count) {
         if (mPagedLayout == null) {
             return false;
@@ -521,6 +553,9 @@
             if (mBrightnessAnimator != null) {
                 mBrightnessAnimator.setPosition(position);
             }
+            if (mQQSFooterActionsAnimator != null) {
+                mQQSFooterActionsAnimator.setPosition(position);
+            }
         }
     }
 
@@ -532,9 +567,9 @@
     @Override
     public void onAnimationAtEnd() {
         mQuickQsPanel.setVisibility(View.INVISIBLE);
-        final int N = mQuickQsViews.size();
+        final int N = mAnimatedQsViews.size();
         for (int i = 0; i < N; i++) {
-            mQuickQsViews.get(i).setVisibility(View.VISIBLE);
+            mAnimatedQsViews.get(i).setVisibility(View.VISIBLE);
         }
     }
 
@@ -542,9 +577,9 @@
     public void onAnimationStarted() {
         updateQQSVisibility();
         if (mOnFirstPage) {
-            final int N = mQuickQsViews.size();
+            final int N = mAnimatedQsViews.size();
             for (int i = 0; i < N; i++) {
-                mQuickQsViews.get(i).setVisibility(View.INVISIBLE);
+                mAnimatedQsViews.get(i).setVisibility(View.INVISIBLE);
             }
         }
     }
@@ -569,9 +604,9 @@
         if (mOtherTilesExpandAnimator != null) {
             mOtherTilesExpandAnimator.resetViewsHeights();
         }
-        final int N2 = mQuickQsViews.size();
+        final int N2 = mAnimatedQsViews.size();
         for (int i = 0; i < N2; i++) {
-            mQuickQsViews.get(i).setVisibility(View.VISIBLE);
+            mAnimatedQsViews.get(i).setVisibility(View.VISIBLE);
         }
     }
 
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/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 57438d1..4d23958 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 FooterActionsView}
+ */
 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);
+        mActionsContainer = requireViewById(R.id.qs_footer_actions);
         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..e7c06e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,35 +16,18 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FOOTER;
 
 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;
@@ -56,137 +39,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 FooterActionsController mFooterActionsController;
     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) {
+            @Named(QS_FOOTER) FooterActionsController footerActionsController) {
         super(view);
-        mUserManager = userManager;
-        mUserInfoController = userInfoController;
-        mActivityStarter = activityStarter;
-        mDeviceProvisionedController = deviceProvisionedController;
         mUserTracker = userTracker;
         mQsPanelController = qsPanelController;
         mQuickQSPanelController = quickQSPanelController;
-        mTunerService = tunerService;
-        mMetricsLogger = metricsLogger;
-        mFalsingManager = falsingManager;
-        mMultiUserSwitchController = multiUserSwitchController;
+        mFooterActionsController = footerActionsController;
 
-        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();
+        mFooterActionsController.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();
+                    mFooterActionsController.updateAnimator(right - left,
+                            mQuickQSPanelController.getNumQuickTiles());
+                }
+        );
+
         mBuildText.setOnLongClickListener(view -> {
             CharSequence buildText = mBuildText.getText();
             if (!TextUtils.isEmpty(buildText)) {
@@ -200,17 +91,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 +107,25 @@
 
     @Override
     public void setExpanded(boolean expanded) {
-        mExpanded = expanded;
-        mView.setExpanded(
-                expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
-    }
-
-    @Override
-    public int getHeight() {
-        return mView.getHeight();
+        mFooterActionsController.setExpanded(expanded);
+        mView.setExpanded(expanded);
     }
 
     @Override
     public void setExpansion(float expansion) {
         mView.setExpansion(expansion);
+        mFooterActionsController.setExpansion(expansion);
     }
 
     @Override
     public void setListening(boolean listening) {
-        if (mListening == listening) {
-            return;
-        }
-
-        mListening = listening;
-        if (mListening) {
-            mUserInfoController.addCallback(mOnUserInfoChangedListener);
-        } else {
-            mUserInfoController.removeCallback(mOnUserInfoChangedListener);
-        }
+        mFooterActionsController.setListening(listening);
     }
 
     @Override
     public void setKeyguardShowing(boolean keyguardShowing) {
         mView.setKeyguardShowing();
+        mFooterActionsController.setKeyguardShowing();
     }
 
     /** */
@@ -267,19 +136,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);
+        mFooterActionsController.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 4e09bc6..4242e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -510,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;
@@ -534,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/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 000fd1c..9f585bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -37,6 +37,7 @@
     void removeCallback(Callback callback);
     TileServices getTileServices();
     void removeTile(String tileSpec);
+    void removeTiles(Collection<String> specs);
     void unmarkTileAsAutoAdded(String tileSpec);
 
     int indexOf(String tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 63124ab..28aa884 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -736,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.
          */
@@ -745,7 +745,7 @@
         }
 
         /**
-         * Set the max number of columns to show
+         * Sets the max number of columns to show
          *
          * @param maxColumns the maximum
          *
@@ -755,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();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 0da4814..42323e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -84,15 +84,15 @@
                 public void onConfigurationChange(Configuration newConfig) {
                     mShouldUseSplitNotificationShade =
                             Utils.shouldUseSplitNotificationShade(getResources());
+                    onConfigurationChanged();
                     if (newConfig.orientation != mLastOrientation) {
                         mLastOrientation = newConfig.orientation;
-                        onScreenRotated();
                         switchTileLayout(false);
                     }
                 }
             };
 
-    protected void onScreenRotated() { }
+    protected void onConfigurationChanged() { }
 
     private final Function1<Boolean, Unit> mMediaHostVisibilityListener = (visible) -> {
         if (mMediaVisibilityChangedListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 240cf93..eff34d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -39,7 +39,6 @@
 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.PluginListener;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
@@ -48,6 +47,7 @@
 import com.android.systemui.qs.external.CustomTileStatePersister;
 import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.qs.external.TileServiceKey;
+import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.UserTracker;
@@ -107,6 +107,8 @@
     private UserTracker mUserTracker;
     private SecureSettings mSecureSettings;
 
+    private final TileServiceRequestController mTileServiceRequestController;
+
     @Inject
     public QSTileHost(Context context,
             StatusBarIconController iconController,
@@ -123,7 +125,8 @@
             UiEventLogger uiEventLogger,
             UserTracker userTracker,
             SecureSettings secureSettings,
-            CustomTileStatePersister customTileStatePersister
+            CustomTileStatePersister customTileStatePersister,
+            TileServiceRequestController.Builder tileServiceRequestControllerBuilder
     ) {
         mIconController = iconController;
         mContext = context;
@@ -134,6 +137,7 @@
         mQSLogger = qsLogger;
         mUiEventLogger = uiEventLogger;
         mBroadcastDispatcher = broadcastDispatcher;
+        mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
 
         mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
         mServices = new TileServices(this, bgLooper, mBroadcastDispatcher, userTracker);
@@ -153,6 +157,7 @@
             tunerService.addTunable(this, TILES_SETTING);
             // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
             mAutoTiles = autoTiles.get();
+            mTileServiceRequestController.init();
         });
     }
 
@@ -172,6 +177,7 @@
         mServices.destroy();
         mPluginManager.removePluginListener(this);
         mDumpManager.unregisterDumpable(TAG);
+        mTileServiceRequestController.destroy();
     }
 
     @Override
@@ -348,6 +354,17 @@
         changeTileSpecs(tileSpecs-> tileSpecs.remove(spec));
     }
 
+    /**
+     * Remove many tiles at once.
+     *
+     * It will only save to settings once (as opposed to {@link QSTileHost#removeTile} called
+     * multiple times).
+     */
+    @Override
+    public void removeTiles(Collection<String> specs) {
+        changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs));
+    }
+
     @Override
     public void unmarkTileAsAutoAdded(String spec) {
         if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
@@ -369,6 +386,7 @@
      * @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
      */
     public void addTile(String spec, int requestPosition) {
+        if (spec.equals("work")) Log.wtfStack(TAG, "Adding work tile");
         changeTileSpecs(tileSpecs -> {
             if (tileSpecs.contains(spec)) return false;
 
@@ -383,6 +401,7 @@
     }
 
     void saveTilesToSettings(List<String> tileSpecs) {
+        if (tileSpecs.contains("work")) Log.wtfStack(TAG, "Saving work tile");
         mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
                 null /* tag */, false /* default */, mCurrentUser,
                 true /* overrideable by restore */);
@@ -512,33 +531,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 +550,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/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 8c7a2cd..92690c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs;
 
 import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
 
 import com.android.internal.logging.MetricsLogger;
@@ -53,6 +54,7 @@
     // brightness is visible only in split shade
     private final QuickQSBrightnessController mBrightnessController;
     private final BrightnessMirrorHandler mBrightnessMirrorHandler;
+    private final FooterActionsController mFooterActionsController;
 
     @Inject
     QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
@@ -61,12 +63,14 @@
             @Named(QUICK_QS_PANEL) MediaHost mediaHost,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
             DumpManager dumpManager,
-            QuickQSBrightnessController quickQSBrightnessController
+            QuickQSBrightnessController quickQSBrightnessController,
+            @Named(QQS_FOOTER) FooterActionsController footerActionsController
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
                 uiEventLogger, qsLogger, dumpManager);
         mBrightnessController = quickQSBrightnessController;
         mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
+        mFooterActionsController = footerActionsController;
     }
 
     @Override
@@ -76,6 +80,8 @@
         mMediaHost.setShowsOnlyActiveMedia(true);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
         mBrightnessController.init(mShouldUseSplitNotificationShade);
+        mFooterActionsController.init();
+        mFooterActionsController.refreshVisibility(mShouldUseSplitNotificationShade);
     }
 
     @Override
@@ -96,6 +102,7 @@
     void setListening(boolean listening) {
         super.setListening(listening);
         mBrightnessController.setListening(listening);
+        mFooterActionsController.setListening(listening);
     }
 
     public boolean isListening() {
@@ -114,8 +121,9 @@
     }
 
     @Override
-    protected void onScreenRotated() {
+    protected void onConfigurationChanged() {
         mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
+        mFooterActionsController.refreshVisibility(mShouldUseSplitNotificationShade);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 8cb9d46..359f3a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -140,9 +140,11 @@
         mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
 
         updateResources();
+        Configuration config = mContext.getResources().getConfiguration();
+        setDatePrivacyContainersWidth(config.orientation == Configuration.ORIENTATION_LANDSCAPE);
+        setSecurityHeaderContainerVisibility(
+                config.orientation == Configuration.ORIENTATION_LANDSCAPE);
 
-        // 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);
@@ -191,6 +193,8 @@
         super.onConfigurationChanged(newConfig);
         updateResources();
         setDatePrivacyContainersWidth(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
+        setSecurityHeaderContainerVisibility(
+                newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
     }
 
     @Override
@@ -211,6 +215,10 @@
         mPrivacyContainer.setLayoutParams(lp);
     }
 
+    private void setSecurityHeaderContainerVisibility(boolean landscape) {
+        mSecurityHeaderView.setVisibility(landscape ? VISIBLE : GONE);
+    }
+
     private void updateBatteryMode() {
         if (mConfigShowBatteryEstimate && !mHasCenterCutout) {
             mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
@@ -318,6 +326,7 @@
                     public void onAnimationAtStart() {
                         super.onAnimationAtStart();
                         mClockDateView.setFreezeSwitching(false);
+                        mClockDateView.setVisibility(View.VISIBLE);
                         setSeparatorVisibility(mShowClockIconsSeparator);
                         // In QQS we never ignore RSSI.
                         mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 6c57c77..9835d17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -182,6 +182,9 @@
         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
@@ -198,6 +201,8 @@
 
         // Ignore privacy icons because they show in the space above QQS
         updatePrivacyIconSlots();
+        mIconContainer.addIgnoredSlot(
+                getResources().getString(com.android.internal.R.string.status_bar_managed_profile));
         mIconContainer.setShouldRestrictIcons(false);
         mStatusBarIconController.addIconGroup(mIconManager);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
new file mode 100644
index 0000000..55da203
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAppTestCases",
+      "options": [
+        {
+          "include-filter": "android.app.cts.TileServiceTest"
+        },
+        {
+          "include-filter": "android.app.cts.BooleanTileServiceTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
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 1770807..3c2f35b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -34,7 +34,6 @@
 import com.android.systemui.R;
 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.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.qs.QSTileHost;
@@ -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/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 2046550..386769c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -26,6 +26,10 @@
 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.FooterActionsController;
+import com.android.systemui.qs.FooterActionsController.ExpansionState;
+import com.android.systemui.qs.FooterActionsControllerBuilder;
+import com.android.systemui.qs.FooterActionsView;
 import com.android.systemui.qs.QSContainerImpl;
 import com.android.systemui.qs.QSFooter;
 import com.android.systemui.qs.QSFooterView;
@@ -49,6 +53,8 @@
 @Module
 public interface QSFragmentModule {
     String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
+    String QQS_FOOTER = "qqs_footer";
+    String QS_FOOTER = "qs_footer";
     String QS_USING_MEDIA_PLAYER = "qs_using_media_player";
 
     /**
@@ -122,6 +128,44 @@
 
     /** */
     @Provides
+    @Named(QS_FOOTER)
+    static FooterActionsView providesQSFooterActionsView(@RootView View view) {
+        return view.findViewById(R.id.qs_footer_actions);
+    }
+
+    /** */
+    @Provides
+    @Named(QQS_FOOTER)
+    static FooterActionsView providesQQSFooterActionsView(@RootView View view) {
+        return view.findViewById(R.id.qqs_footer_actions);
+    }
+
+    /** */
+    @Provides
+    @Named(QQS_FOOTER)
+    static FooterActionsController providesQQSFooterActionsController(
+            FooterActionsControllerBuilder footerActionsControllerBuilder,
+            @Named(QQS_FOOTER) FooterActionsView qqsFooterActionsView) {
+        return footerActionsControllerBuilder
+                .withView(qqsFooterActionsView)
+                .withButtonsVisibleWhen(ExpansionState.COLLAPSED)
+                .build();
+    }
+
+    /** */
+    @Provides
+    @Named(QS_FOOTER)
+    static FooterActionsController providesQSFooterActionsController(
+            FooterActionsControllerBuilder footerActionsControllerBuilder,
+            @Named(QS_FOOTER) FooterActionsView qsFooterActionsView) {
+        return footerActionsControllerBuilder
+                .withView(qsFooterActionsView)
+                .withButtonsVisibleWhen(ExpansionState.EXPANDED)
+                .build();
+    }
+
+    /** */
+    @Provides
     @QSScope
     static QSFooter providesQSFooter(QSFooterViewController qsFooterViewController) {
         qsFooterViewController.init();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 396eca5..5bd02cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -63,6 +63,7 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.inject.Inject;
 
@@ -98,6 +99,8 @@
 
     private final TileServiceKey mKey;
 
+    private final AtomicBoolean mInitialDefaultIconFetched = new AtomicBoolean(false);
+
     private CustomTile(
             QSHost host,
             Looper backgroundLooper,
@@ -128,6 +131,12 @@
     @Override
     protected void handleInitialize() {
         updateDefaultTileAndIcon();
+        if (mInitialDefaultIconFetched.compareAndSet(false, true)) {
+            if (mDefaultIcon == null) {
+                Log.w(TAG, "No default icon for " + getTileSpec() + ", destroying tile");
+                mHost.removeTile(getTileSpec());
+            }
+        }
         if (mServiceManager.isToggleableTile()) {
             // Replace states with BooleanState
             resetStates();
@@ -213,9 +222,18 @@
         mHandler.post(this::updateDefaultTileAndIcon);
     }
 
+    /**
+     * Custom tile is considered available if there is a default icon (obtained from PM).
+     *
+     * It will return {@code true} before initialization, so tiles are not destroyed prematurely.
+     */
     @Override
     public boolean isAvailable() {
-        return mDefaultIcon != null;
+        if (mInitialDefaultIconFetched.get()) {
+            return mDefaultIcon != null;
+        } else {
+            return true;
+        }
     }
 
     public int getUser() {
@@ -394,7 +412,7 @@
             tileState = Tile.STATE_UNAVAILABLE;
         }
         state.state = tileState;
-        Drawable drawable;
+        Drawable drawable = null;
         try {
             drawable = mTile.getIcon().loadDrawable(mUserContext);
         } catch (Exception e) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
new file mode 100644
index 0000000..baf3018
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.external
+
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.view.WindowInsets
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.qs.QSTileView
+import com.android.systemui.qs.tileimpl.QSIconViewImpl
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import com.android.systemui.qs.tileimpl.QSTileViewImpl
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/**
+ * Dialog to present to the user to ask for authorization to add a [TileService].
+ */
+class TileRequestDialog(
+    context: Context
+) : SystemUIDialog(context, R.style.TileRequestDialog) {
+
+    companion object {
+        internal val CONTENT_ID = R.id.content
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        window?.apply {
+            attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
+            attributes.receiveInsetsIgnoringZOrder = true
+            setLayout(
+                    context.resources
+                            .getDimensionPixelSize(R.dimen.qs_tile_service_request_dialog_width),
+                    WRAP_CONTENT
+            )
+        }
+    }
+
+    /**
+     * Set the data of the tile to add, to show the user.
+     */
+    fun setTileData(tileData: TileData) {
+        val ll = (LayoutInflater
+                        .from(context)
+                        .inflate(R.layout.tile_service_request_dialog, null)
+                        as ViewGroup).apply {
+                    requireViewById<TextView>(R.id.text).apply {
+                        text = context
+                                .getString(R.string.qs_tile_request_dialog_text, tileData.appName)
+                    }
+                    addView(
+                            createTileView(tileData),
+                            context.resources.getDimensionPixelSize(
+                                    R.dimen.qs_tile_service_request_tile_width),
+                            context.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size)
+                    )
+        }
+        val spacing = context.resources.getDimensionPixelSize(
+                R.dimen.qs_tile_service_request_content_space
+        )
+        setView(ll, spacing, spacing, spacing, spacing / 2)
+    }
+
+    private fun createTileView(tileData: TileData): QSTileView {
+        val tile = QSTileViewImpl(context, QSIconViewImpl(context), true)
+        val state = QSTile.BooleanState().apply {
+            label = tileData.label
+            icon = tileData.icon?.loadDrawable(context)?.let {
+                QSTileImpl.DrawableIcon(it)
+            } ?: ResourceIcon.get(R.drawable.android)
+        }
+        tile.onStateChanged(state)
+        tile.isSelected = true
+        return tile
+    }
+
+    /**
+     * Data bundle of information to show the user.
+     *
+     * @property appName Name of the app requesting their [TileService] to be added.
+     * @property label Label of the tile.
+     * @property icon Icon for the tile.
+     */
+    data class TileData(
+        val appName: CharSequence,
+        val label: CharSequence,
+        val icon: Icon?
+    )
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
new file mode 100644
index 0000000..e6da234
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
@@ -0,0 +1,142 @@
+/*
+ * 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.external
+
+import android.app.Dialog
+import android.content.ComponentName
+import android.content.DialogInterface
+import android.graphics.drawable.Icon
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.R
+import java.io.PrintWriter
+import java.util.function.Consumer
+import javax.inject.Inject
+
+private const val TAG = "TileServiceRequestController"
+
+/**
+ * Controller to interface between [TileRequestDialog] and [QSTileHost].
+ */
+class TileServiceRequestController constructor(
+    private val qsTileHost: QSTileHost,
+    private val commandRegistry: CommandRegistry,
+    private val dialogCreator: () -> TileRequestDialog = { TileRequestDialog(qsTileHost.context) }
+) {
+
+    companion object {
+        // Temporary return values while there's no API
+        internal const val ADD_TILE = 0
+        internal const val DONT_ADD_TILE = 1
+        internal const val TILE_ALREADY_ADDED = 2
+        internal const val DISMISSED = 3
+    }
+
+    fun init() {
+        commandRegistry.registerCommand("tile-service-add") { TileServiceRequestCommand() }
+    }
+
+    fun destroy() {
+        commandRegistry.unregisterCommand("tile-service-add")
+    }
+
+    private fun addTile(componentName: ComponentName) {
+        qsTileHost.addTile(componentName, true)
+    }
+
+    @VisibleForTesting
+    internal fun requestTileAdd(
+        componentName: ComponentName,
+        appName: CharSequence,
+        label: CharSequence,
+        icon: Icon?,
+        callback: Consumer<Int>
+    ) {
+        if (isTileAlreadyAdded(componentName)) {
+            callback.accept(TILE_ALREADY_ADDED)
+            return
+        }
+        val dialogResponse = object : Consumer<Int> {
+            override fun accept(response: Int) {
+                if (response == ADD_TILE) {
+                    addTile(componentName)
+                }
+                callback.accept(response)
+            }
+        }
+        val tileData = TileRequestDialog.TileData(appName, label, icon)
+        createDialog(tileData, dialogResponse).show()
+    }
+
+    private fun createDialog(
+        tileData: TileRequestDialog.TileData,
+        responseHandler: Consumer<Int>
+    ): SystemUIDialog {
+        val dialogClickListener = DialogInterface.OnClickListener { _, which ->
+            if (which == Dialog.BUTTON_POSITIVE) {
+                responseHandler.accept(ADD_TILE)
+            } else {
+                responseHandler.accept(DONT_ADD_TILE)
+            }
+        }
+        return dialogCreator().apply {
+            setTileData(tileData)
+            setShowForAllUsers(true)
+            setCanceledOnTouchOutside(true)
+            setOnCancelListener { responseHandler.accept(DISMISSED) }
+            setPositiveButton(R.string.qs_tile_request_dialog_add, dialogClickListener)
+            setNegativeButton(R.string.qs_tile_request_dialog_not_add, dialogClickListener)
+        }
+    }
+
+    private fun isTileAlreadyAdded(componentName: ComponentName): Boolean {
+        val spec = CustomTile.toSpec(componentName)
+        return qsTileHost.indexOf(spec) != -1
+    }
+
+    inner class TileServiceRequestCommand : Command {
+        override fun execute(pw: PrintWriter, args: List<String>) {
+            val componentName: ComponentName = ComponentName.unflattenFromString(args[0])
+                    ?: run {
+                        Log.w(TAG, "Malformed componentName ${args[0]}")
+                        return
+                    }
+            requestTileAdd(componentName, args[1], args[2], null) {
+                Log.d(TAG, "Response: $it")
+            }
+        }
+
+        override fun help(pw: PrintWriter) {
+            pw.println("Usage: adb shell cmd statusbar tile-service-add " +
+                    "<componentName> <appName> <label>")
+        }
+    }
+
+    @SysUISingleton
+    class Builder @Inject constructor(
+        private val commandRegistry: CommandRegistry
+    ) {
+        fun create(qsTileHost: QSTileHost): TileServiceRequestController {
+            return TileServiceRequestController(qsTileHost, commandRegistry)
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 2e771d6..b1cd03c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -116,6 +116,9 @@
                     : icon.getInvisibleDrawable(mContext) : null;
             int padding = icon != null ? icon.getPadding() : 0;
             if (d != null) {
+                if (d.getConstantState() != null) {
+                    d = d.getConstantState().newDrawable();
+                }
                 d.setAutoMirrored(false);
                 d.setLayoutDirection(getLayoutDirection());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 4616be8..70e3a2b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -105,7 +105,7 @@
     protected final ActivityStarter mActivityStarter;
     private final UiEventLogger mUiEventLogger;
     private final FalsingManager mFalsingManager;
-    private final QSLogger mQSLogger;
+    protected final QSLogger mQSLogger;
     private volatile int mReadyState;
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
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..ee5e4df 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))
@@ -289,6 +286,10 @@
         return labelContainer
     }
 
+    override fun getLabel(): View {
+        return label
+    }
+
     override fun getSecondaryLabel(): View {
         return secondaryLabel
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 92ae88d..cc9e748 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -122,8 +122,9 @@
 
     @Override
     protected void handleClick(@Nullable View view) {
-        boolean canConfigMobileData = mAccessPointController.canConfigMobileData();
-        mHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
+        mHandler.post(() -> mInternetDialogFactory.create(true,
+                mAccessPointController.canConfigMobileData(),
+                mAccessPointController.canConfigWifi()));
     }
 
     @Override
@@ -438,7 +439,7 @@
                 state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
             }
         } else if (cb.mNoDefaultNetwork) {
-            if (cb.mNoNetworksAvailable) {
+            if (cb.mNoNetworksAvailable || !cb.mEnabled) {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
                 state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
             } else {
@@ -498,7 +499,7 @@
             state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
             state.secondaryLabel = r.getString(R.string.status_bar_airplane);
         } else if (cb.mNoDefaultNetwork) {
-            if (cb.mNoNetworksAvailable) {
+            if (cb.mNoNetworksAvailable || !mSignalCallback.mWifiInfo.mEnabled) {
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
                 state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 82b6c0c..d9919bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -131,22 +131,16 @@
                 Intent intent = new Intent(mContext, WalletActivity.class)
                         .setAction(Intent.ACTION_VIEW)
                         .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
-                if (mKeyguardStateController.isUnlocked()) {
-                    mActivityStarter.startActivity(intent, true /* dismissShade */,
-                            animationController);
-                } else {
-                    mHost.collapsePanels();
-                    // Do not use ActivityStarter here because the WalletActivity is required to be
-                    // started without prompting keyguard when the device is locked.
-                    mContext.startActivity(intent);
-                }
+                mActivityStarter.startActivity(intent, true /* dismissShade */,
+                        animationController, true /* showOverLockscreenWhenLocked */);
             } else {
-                if (mController.getWalletClient().createWalletIntent() == null) {
+                Intent intent = mController.getWalletClient().createWalletIntent();
+                if (intent == null) {
                     Log.w(TAG, "Could not get intent of the wallet app.");
                     return;
                 }
                 mActivityStarter.postStartActivityDismissingKeyguard(
-                        mController.getWalletClient().createWalletIntent(),
+                        intent,
                         /* delay= */ 0,
                         animationController);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 04437ea..b718ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -39,6 +40,8 @@
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
+import java.util.function.Consumer;
+
 import javax.inject.Inject;
 
 /**
@@ -75,6 +78,7 @@
         private View mCurrentUserView;
         private final UiEventLogger mUiEventLogger;
         private final FalsingManager mFalsingManager;
+        private Consumer<UserSwitcherController.UserRecord> mClickCallback;
 
         @Inject
         public Adapter(Context context, UserSwitcherController controller,
@@ -92,6 +96,10 @@
             return createUserDetailItemView(convertView, parent, item);
         }
 
+        public void injectCallback(Consumer<UserSwitcherController.UserRecord> clickCallback) {
+            mClickCallback = clickCallback;
+        }
+
         public UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent,
                 UserSwitcherController.UserRecord item) {
             UserDetailItemView v = UserDetailItemView.convertOrInflate(
@@ -150,6 +158,7 @@
                 return;
             }
 
+            Trace.beginSection("UserDetailView.Adapter#onClick");
             UserSwitcherController.UserRecord tag =
                     (UserSwitcherController.UserRecord) view.getTag();
             if (tag.isDisabledByAdmin) {
@@ -167,6 +176,14 @@
                 }
                 onUserListItemClicked(tag);
             }
+            Trace.endSection();
+            if (mClickCallback != null) {
+                mClickCallback.accept(tag);
+            }
+        }
+
+        public void linkToViewGroup(ViewGroup viewGroup) {
+            PseudoGridView.ViewGroupAdapterBridge.link(viewGroup, this);
         }
     }
 }
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 e346044..99eb5b6 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
@@ -16,16 +16,11 @@
 
 package com.android.systemui.qs.tiles.dialog;
 
-import static com.android.wifitrackerlib.WifiEntry.SECURITY_NONE;
-import static com.android.wifitrackerlib.WifiEntry.SECURITY_OWE;
-
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.text.Html;
 import android.text.TextUtils;
-import android.util.Log;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -34,8 +29,10 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.Utils;
 import com.android.settingslib.wifi.WifiUtils;
 import com.android.systemui.R;
@@ -43,7 +40,6 @@
 
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
 
 /**
  * Adapter for showing Wi-Fi networks.
@@ -54,9 +50,10 @@
     private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
     private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
     private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final InternetDialogController mInternetDialogController;
+    private List<WifiEntry> mWifiEntries;
+    private int mWifiEntriesCount;
 
     protected View mHolderView;
     protected Context mContext;
@@ -76,53 +73,31 @@
 
     @Override
     public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) {
-        List<WifiEntry> wifiList = getWifiEntryList();
-        if (wifiList != null && wifiList.size() != 0) {
-            int count = getItemCount();
-            if (wifiList.size() > count) {
-                wifiList = getWifiEntryList().subList(0, count - 1);
-            }
-
-            if (position < wifiList.size()) {
-                viewHolder.onBind(wifiList.get(position));
-            }
-        } else if (DEBUG) {
-            Log.d(TAG, "onBindViewHolder, Wi-Fi entry list = null");
+        if (mWifiEntries == null || position >= mWifiEntriesCount) {
+            return;
         }
-    }
-
-    private List<WifiEntry> getWifiEntryList() {
-        if (mInternetDialogController.getWifiEntryList() == null) {
-            return null;
-        }
-
-        return mInternetDialogController.getWifiEntryList().stream()
-                .filter(wifiEntry -> !wifiEntry.isDefaultNetwork())
-                .limit(getItemCount())
-                .collect(Collectors.toList());
+        viewHolder.onBind(mWifiEntries.get(position));
     }
 
     /**
-     * The total number of networks (mobile network and entries of Wi-Fi) should be four in
-     * {@link InternetDialog}.
+     * Updates the Wi-Fi networks.
      *
-     * Airplane mode is ON (mobile network is gone):
-     *   Return four Wi-Fi's entries if no default Wi-Fi.
-     *   Return three Wi-Fi's entries if one default Wi-Fi.
-     * Airplane mode is OFF (mobile network is visible):
-     *   Return three Wi-Fi's entries if no default Wi-Fi.
-     *   Return two Wi-Fi's entries if one default Wi-Fi.
+     * @param wifiEntries the updated Wi-Fi entries.
+     * @param wifiEntriesCount the total number of Wi-Fi entries.
+     */
+    public void setWifiEntries(@Nullable List<WifiEntry> wifiEntries, int wifiEntriesCount) {
+        mWifiEntries = wifiEntries;
+        mWifiEntriesCount = wifiEntriesCount;
+    }
+
+    /**
+     * Gets the total number of Wi-Fi networks.
      *
-     * @return The total number of networks.
+     * @return The total number of Wi-Fi entries.
      */
     @Override
     public int getItemCount() {
-        final boolean hasDefaultWifi = mInternetDialogController.getDefaultWifiEntry() != null;
-        if (mInternetDialogController.isAirplaneModeEnabled()) {
-            return hasDefaultWifi ? 3 : 4;
-        } else {
-            return hasDefaultWifi ? 2 : 3;
-        }
+        return mWifiEntriesCount;
     }
 
     /**
@@ -136,10 +111,11 @@
         final ImageView mWifiIcon;
         final TextView mWifiTitleText;
         final TextView mWifiSummaryText;
-        final ImageView mWifiLockedIcon;
+        final ImageView mWifiEndIcon;
         final Context mContext;
         final InternetDialogController mInternetDialogController;
 
+        @VisibleForTesting
         protected WifiUtils.InternetIconInjector mWifiIconInjector;
 
         InternetViewHolder(View view, InternetDialogController internetDialogController) {
@@ -152,28 +128,25 @@
             mWifiIcon = view.requireViewById(R.id.wifi_icon);
             mWifiTitleText = view.requireViewById(R.id.wifi_title);
             mWifiSummaryText = view.requireViewById(R.id.wifi_summary);
-            mWifiLockedIcon = view.requireViewById(R.id.wifi_locked_icon);
+            mWifiEndIcon = view.requireViewById(R.id.wifi_end_icon);
             mWifiIconInjector = mInternetDialogController.getWifiIconInjector();
         }
 
-        void onBind(WifiEntry wifiEntry) {
-            int security = wifiEntry.getSecurity();
-            try {
-                mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
-                if (isOpenNetwork(security)) {
-                    mWifiLockedIcon.setVisibility(View.GONE);
-                } else {
-                    mWifiLockedIcon.setVisibility(View.VISIBLE);
-                    mWifiLockedIcon.setImageDrawable(
-                            mContext.getDrawable(R.drawable.ic_friction_lock_closed));
-                }
-            } catch (Throwable throwable) {
-                throwable.printStackTrace();
-            }
-
+        void onBind(@NonNull WifiEntry wifiEntry) {
+            mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
             setWifiNetworkLayout(wifiEntry.getTitle(),
                     Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY));
 
+            final int connectedState = wifiEntry.getConnectedState();
+            final int security = wifiEntry.getSecurity();
+            updateEndIcon(connectedState, security);
+
+            if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
+                mWifiListLayout.setOnClickListener(
+                        v -> mInternetDialogController.launchWifiNetworkDetailsSetting(
+                                wifiEntry.getKey()));
+                return;
+            }
             mWifiListLayout.setOnClickListener(v -> {
                 if (wifiEntry.shouldEditBeforeConnect()) {
                     final Intent intent = new Intent(ACTION_WIFI_DIALOG);
@@ -187,28 +160,20 @@
             });
         }
 
-        /** Return true if this is an open network AccessPoint. */
-        boolean isOpenNetwork(int security) {
-            return security == SECURITY_NONE
-                    || security == SECURITY_OWE;
-        }
-
         void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
-            mWifiNetworkLayout.setVisibility(View.VISIBLE);
             mWifiTitleText.setText(title);
             if (TextUtils.isEmpty(summary)) {
-                mWifiTitleText.setGravity(Gravity.CENTER);
                 mWifiSummaryText.setVisibility(View.GONE);
                 return;
-            } else {
-                mWifiTitleText.setGravity(Gravity.BOTTOM);
-                mWifiSummaryText.setGravity(Gravity.TOP);
-                mWifiSummaryText.setVisibility(View.VISIBLE);
             }
+            mWifiSummaryText.setVisibility(View.VISIBLE);
             mWifiSummaryText.setText(summary);
         }
 
-        Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) throws Throwable {
+        Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) {
+            if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
+                return null;
+            }
             final Drawable drawable = mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(),
                     wifiEntry.getLevel());
             if (drawable == null) {
@@ -220,5 +185,20 @@
             shared.set(drawable);
             return shared.get();
         }
+
+        void updateEndIcon(int connectedState, int security) {
+            Drawable drawable = null;
+            if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
+                drawable = mContext.getDrawable(R.drawable.ic_settings_24dp);
+            } else if (security != WifiEntry.SECURITY_NONE && security != WifiEntry.SECURITY_OWE) {
+                drawable = mContext.getDrawable(R.drawable.ic_friction_lock_closed);
+            }
+            if (drawable == null) {
+                mWifiEndIcon.setVisibility(View.GONE);
+                return;
+            }
+            mWifiEndIcon.setVisibility(View.VISIBLE);
+            mWifiEndIcon.setImageDrawable(drawable);
+        }
     }
 }
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 a63d1f8..b1db8a9 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
@@ -21,13 +21,11 @@
 
 import android.app.AlertDialog;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.wifi.ScanResult;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
@@ -51,11 +49,12 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
-import android.widget.Space;
 import android.widget.Switch;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -92,7 +91,7 @@
     @VisibleForTesting
     protected View mDialogView;
     @VisibleForTesting
-    protected WifiEntry mConnectedWifiEntry;
+    protected boolean mCanConfigWifi;
 
     private InternetDialogFactory mInternetDialogFactory;
     private SubscriptionManager mSubscriptionManager;
@@ -105,14 +104,15 @@
     private TextView mInternetDialogSubTitle;
     private View mDivider;
     private ProgressBar mProgressBar;
+    private LinearLayout mInternetDialogLayout;
     private LinearLayout mInternetListLayout;
     private LinearLayout mConnectedWifListLayout;
     private LinearLayout mConnectedWifList;
     private LinearLayout mMobileNetworkLayout;
     private LinearLayout mMobileNetworkList;
     private LinearLayout mTurnWifiOnLayout;
+    private TextView mWifiToggleTitleText;
     private LinearLayout mSeeAllLayout;
-    private Space mSpace;
     private RecyclerView mWifiRecyclerView;
     private ImageView mConnectedWifiIcon;
     private ImageView mWifiSettingsIcon;
@@ -126,9 +126,14 @@
     private Button mDoneButton;
     private Drawable mBackgroundOn;
     private int mListMaxHeight;
+    private int mLayoutWidth;
     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private boolean mCanConfigMobileData;
 
+    // Wi-Fi entries
+    protected WifiEntry mConnectedWifiEntry;
+    protected int mWifiEntriesCount;
+
     // Wi-Fi scanning progress bar
     protected boolean mIsProgressBarVisible;
     protected boolean mIsSearchingHidden;
@@ -142,16 +147,17 @@
 
     private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
         // Set max height for list
-        if (mInternetListLayout.getHeight() > mListMaxHeight) {
-            ViewGroup.LayoutParams params = mInternetListLayout.getLayoutParams();
+        if (mInternetDialogLayout.getHeight() > mListMaxHeight) {
+            ViewGroup.LayoutParams params = mInternetDialogLayout.getLayoutParams();
             params.height = mListMaxHeight;
-            mInternetListLayout.setLayoutParams(params);
+            mInternetDialogLayout.setLayoutParams(params);
         }
     };
 
     public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
             InternetDialogController internetDialogController, boolean canConfigMobileData,
-            boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
+            boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
+            @Main Handler handler) {
         super(context, R.style.Theme_SystemUI_Dialog_Internet);
         if (DEBUG) {
             Log.d(TAG, "Init InternetDialog");
@@ -165,6 +171,7 @@
         mTelephonyManager = mInternetDialogController.getTelephonyManager();
         mWifiManager = mInternetDialogController.getWifiManager();
         mCanConfigMobileData = canConfigMobileData;
+        mCanConfigWifi = canConfigWifi;
 
         mLayoutManager = new LinearLayoutManager(mContext) {
             @Override
@@ -174,6 +181,8 @@
         };
         mListMaxHeight = context.getResources().getDimensionPixelSize(
                 R.dimen.internet_dialog_list_max_height);
+        mLayoutWidth = context.getResources().getDimensionPixelSize(
+                R.dimen.internet_dialog_list_max_width);
         mUiEventLogger = uiEventLogger;
         mAdapter = new InternetAdapter(mInternetDialogController);
         if (!aboveStatusBar) {
@@ -200,11 +209,14 @@
         layoutParams.setFitInsetsIgnoringVisibility(true);
         window.setAttributes(layoutParams);
         window.setContentView(mDialogView);
-        window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        //Only fix the width for large screen or tablet.
+        window.setLayout(mContext.getResources().getDimensionPixelSize(
+                R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT);
         window.setWindowAnimations(R.style.Animation_InternetDialog);
         window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         window.addFlags(FLAG_LAYOUT_NO_LIMITS);
 
+        mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog);
         mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
         mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
         mDivider = mDialogView.requireViewById(R.id.divider);
@@ -213,6 +225,7 @@
         mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
         mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list);
         mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+        mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
         mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
         mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list);
         mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
@@ -221,7 +234,6 @@
         mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
         mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
         mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
-        mSpace = mDialogView.requireViewById(R.id.space);
         mDoneButton = mDialogView.requireViewById(R.id.done);
         mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
         mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
@@ -229,7 +241,7 @@
         mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
         mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
         mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
-        mInternetListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
+        mInternetDialogLayout.getViewTreeObserver().addOnGlobalLayoutListener(
                 mInternetListLayoutListener);
         mInternetDialogTitle.setText(getDialogTitleText());
         mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
@@ -246,7 +258,19 @@
         if (DEBUG) {
             Log.d(TAG, "onStart");
         }
-        mInternetDialogController.onStart(this);
+        mInternetDialogController.onStart(this, mCanConfigWifi);
+        if (!mCanConfigWifi) {
+            hideWifiViews();
+        }
+    }
+
+    @VisibleForTesting
+    void hideWifiViews() {
+        setProgressBarVisible(false);
+        mTurnWifiOnLayout.setVisibility(View.GONE);
+        mConnectedWifListLayout.setVisibility(View.GONE);
+        mWifiRecyclerView.setVisibility(View.GONE);
+        mSeeAllLayout.setVisibility(View.GONE);
     }
 
     @Override
@@ -285,21 +309,28 @@
         } else {
             mInternetDialogSubTitle.setText(getSubtitleText());
         }
-        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);
+
+        if (!mCanConfigWifi) {
+            return;
+        }
+
+        showProgressBar();
+        final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
+        final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
+        updateWifiToggle(isWifiEnabled, isDeviceLocked);
+        updateConnectedWifi(isWifiEnabled, isDeviceLocked);
+
+        final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0)
+                ? View.GONE : View.VISIBLE;
+        mWifiRecyclerView.setVisibility(visibility);
+        mSeeAllLayout.setVisibility(visibility);
     }
 
     private void setOnClickListener() {
         mMobileNetworkLayout.setOnClickListener(v -> {
-            if (mInternetDialogController.isMobileDataEnabled()) {
+            if (mInternetDialogController.isMobileDataEnabled()
+                    && !mInternetDialogController.isDeviceLocked()) {
                 if (!mInternetDialogController.activeNetworkIsCellular()) {
                     mInternetDialogController.connectCarrierNetwork();
                 }
@@ -320,7 +351,6 @@
                 (buttonView, isChecked) -> {
                     buttonView.setChecked(isChecked);
                     mWifiManager.setWifiEnabled(isChecked);
-                    mSpace.setVisibility(isChecked ? View.GONE : View.VISIBLE);
                 });
         mDoneButton.setOnClickListener(v -> dismiss());
     }
@@ -358,17 +388,29 @@
         }
     }
 
-    private void setConnectedWifiLayout() {
-        if (!mWifiManager.isWifiEnabled() || mConnectedWifiEntry == null) {
+    private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
+        mWiFiToggle.setChecked(isWifiEnabled);
+        if (isDeviceLocked && mInternetDialogController.isNightMode()) {
+            int titleColor = mConnectedWifiEntry != null ? mContext.getColor(
+                    R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+                    mContext, android.R.attr.textColorPrimary);
+            mWifiToggleTitleText.setTextColor(titleColor);
+        }
+        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());
+        mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
+        mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
         mConnectedWifiIcon.setImageDrawable(
-                mInternetDialogController.getConnectedWifiDrawable(mConnectedWifiEntry));
+                mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
         if (mInternetDialogController.isNightMode()) {
             mConnectedWifiTitleText.setTextColor(
                     mContext.getColor(R.color.connected_network_primary_color));
@@ -381,7 +423,10 @@
     }
 
     void onClickConnectedWifi() {
-        mInternetDialogController.launchWifiNetworkDetailsSetting();
+        if (mConnectedWifiEntry == null) {
+            return;
+        }
+        mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey());
     }
 
     void onClickSeeMoreButton() {
@@ -409,22 +454,14 @@
         return mInternetDialogController.getMobileNetworkSummary();
     }
 
-    String getConnectedWifiTitle() {
-        return mInternetDialogController.getDefaultWifiTitle();
-    }
-
-    String getConnectedWifiSummary() {
-        return mInternetDialogController.getDefaultWifiSummary();
-    }
-
     protected void showProgressBar() {
-        if (mWifiManager == null || !mWifiManager.isWifiEnabled()) {
+        if (mWifiManager == null || !mWifiManager.isWifiEnabled()
+                || mInternetDialogController.isDeviceLocked()) {
             setProgressBarVisible(false);
             return;
         }
         setProgressBarVisible(true);
-        List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
-        if (wifiScanResults != null && wifiScanResults.size() > 0) {
+        if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) {
             mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
         } else if (!mIsSearchingHidden) {
             mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
@@ -452,8 +489,7 @@
     }
 
     private void showTurnOffMobileDialog() {
-        CharSequence carrierName =
-                mSubscriptionManager.getDefaultDataSubscriptionInfo().getCarrierName();
+        CharSequence carrierName = getMobileNetworkTitle();
         boolean isInService = mInternetDialogController.isVoiceStateInService();
         if (TextUtils.isEmpty(carrierName) || !isInService) {
             carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
@@ -509,8 +545,8 @@
     }
 
     @Override
+    @WorkerThread
     public void onDataConnectionStateChanged(int state, int networkType) {
-        mAdapter.notifyDataSetChanged();
         mHandler.post(() -> updateDialog());
     }
 
@@ -525,10 +561,16 @@
     }
 
     @Override
-    public void onAccessPointsChanged(List<WifiEntry> wifiEntryList, WifiEntry connectedEntry) {
+    @WorkerThread
+    public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
+            @Nullable WifiEntry connectedEntry) {
         mConnectedWifiEntry = connectedEntry;
-        mAdapter.notifyDataSetChanged();
-        mHandler.post(() -> updateDialog());
+        mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+        mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
+        mHandler.post(() -> {
+            mAdapter.notifyDataSetChanged();
+            updateDialog();
+        });
     }
 
     @Override
@@ -541,24 +583,6 @@
         }
     }
 
-    @Override
-    public void onWifiStateReceived(Context context, Intent intent) {
-        if (intent == null) {
-            return;
-        }
-
-        String action = intent.getAction();
-        if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
-            mInternetDialogController.scanWifiAccessPoints();
-            showProgressBar();
-            return;
-        }
-
-        if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            mHandler.post(() -> updateDialog());
-        }
-    }
-
     public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
         @UiEvent(doc = "The Internet dialog became visible on the screen.")
         INTERNET_DIALOG_SHOW(843);
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 890dcfd..70f52ad 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
@@ -32,7 +32,6 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.wifi.ScanResult;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.provider.Settings;
@@ -53,6 +52,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -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 =
@@ -105,6 +108,8 @@
             R.string.all_network_unavailable;
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    static final int MAX_WIFI_ENTRY_COUNT = 4;
+
     private WifiManager mWifiManager;
     private Context mContext;
     private SubscriptionManager mSubscriptionManager;
@@ -119,7 +124,8 @@
     private AccessPointController mAccessPointController;
     private IntentFilter mConnectionStateFilter;
     private InternetDialogCallback mCallback;
-    private List<WifiEntry> mWifiEntry;
+    private WifiEntry mConnectedEntry;
+    private int mWifiEntriesCount;
     private UiEventLogger mUiEventLogger;
     private BroadcastDispatcher mBroadcastDispatcher;
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -129,13 +135,15 @@
     @VisibleForTesting
     protected ActivityStarter mActivityStarter;
     @VisibleForTesting
-    protected WifiEntry mConnectedEntry;
-    @VisibleForTesting
     protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
     @VisibleForTesting
     protected InternetTelephonyCallback mInternetTelephonyCallback;
     @VisibleForTesting
     protected WifiUtils.InternetIconInjector mWifiIconInjector;
+    @VisibleForTesting
+    protected boolean mCanConfigWifi;
+    @VisibleForTesting
+    protected KeyguardStateController mKeyguardStateController;
 
     private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -161,7 +169,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");
         }
@@ -175,9 +183,8 @@
         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);
         mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
         mUiEventLogger = uiEventLogger;
         mActivityStarter = starter;
@@ -186,7 +193,7 @@
         mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext);
     }
 
-    void onStart(@NonNull InternetDialogCallback callback) {
+    void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
         if (DEBUG) {
             Log.d(TAG, "onStart");
         }
@@ -210,6 +217,7 @@
         mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), new DataConnectivityListener(), mHandler);
+        mCanConfigWifi = canConfigWifi;
         scanWifiAccessPoints();
     }
 
@@ -240,8 +248,7 @@
         return new Intent(ACTION_NETWORK_PROVIDER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     }
 
-    protected Intent getWifiDetailsSettingsIntent() {
-        String key = mConnectedEntry == null ? null : mConnectedEntry.getKey();
+    protected Intent getWifiDetailsSettingsIntent(String key) {
         if (TextUtils.isEmpty(key)) {
             if (DEBUG) {
                 Log.d(TAG, "connected entry's key is empty");
@@ -263,7 +270,7 @@
             return null;
         }
 
-        if (!mWifiManager.isWifiEnabled()) {
+        if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) {
             // When the airplane mode is off and Wi-Fi is disabled.
             //   Sub-Title: Wi-Fi is off
             if (DEBUG) {
@@ -272,12 +279,20 @@
             return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF);
         }
 
-        final List<ScanResult> wifiList = mWifiManager.getScanResults();
-        if (wifiList != null && wifiList.size() != 0) {
-            return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT);
+        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);
         }
 
-        if (isProgressBarVisible) {
+        if (mConnectedEntry != null || mWifiEntriesCount > 0) {
+            return mCanConfigWifi ? mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT) : null;
+        }
+
+        if (mCanConfigWifi && isProgressBarVisible) {
             // When the Wi-Fi scan result callback is received
             //   Sub-Title: Searching for networks...
             return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS);
@@ -301,7 +316,7 @@
             return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
         }
 
-        if (!isMobileDataEnabled()) {
+        if (mCanConfigWifi && !isMobileDataEnabled()) {
             if (DEBUG) {
                 Log.d(TAG, "Mobile data off");
             }
@@ -315,12 +330,18 @@
             return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
         }
 
-        return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+        if (mCanConfigWifi) {
+            return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+        }
+        return null;
     }
 
-    Drawable getConnectedWifiDrawable(@NonNull WifiEntry wifiEntry) {
+    Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) {
+        if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
+            return null;
+        }
         final Drawable drawable =
-                mWifiIconInjector.getIcon(false /* noInternet*/, wifiEntry.getLevel());
+                mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel());
         if (drawable == null) {
             return null;
         }
@@ -372,7 +393,8 @@
             level += 1;
             numLevels += 1;
         }
-        return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, false);
+        return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON,
+                !isMobileDataEnabled());
     }
 
     Drawable getSignalStrengthIcon(Context context, int level, int numLevels,
@@ -533,33 +555,13 @@
         return summary;
     }
 
-    String getDefaultWifiTitle() {
-        if (getDefaultWifiEntry() == null) {
-            if (DEBUG) {
-                Log.d(TAG, "connected entry is null");
-            }
-            return "";
-        }
-        return getDefaultWifiEntry().getTitle();
-    }
-
-    String getDefaultWifiSummary() {
-        if (getDefaultWifiEntry() == null) {
-            if (DEBUG) {
-                Log.d(TAG, "connected entry is null");
-            }
-            return "";
-        }
-        return getDefaultWifiEntry().getSummary(false);
-    }
-
     void launchNetworkSetting() {
         mCallback.dismissDialog();
         mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0);
     }
 
-    void launchWifiNetworkDetailsSetting() {
-        Intent intent = getWifiDetailsSettingsIntent();
+    void launchWifiNetworkDetailsSetting(String key) {
+        Intent intent = getWifiDetailsSettingsIntent(key);
         if (intent != null) {
             mCallback.dismissDialog();
             mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
@@ -574,17 +576,6 @@
         }
     }
 
-    List<WifiEntry> getWifiEntryList() {
-        return mWifiEntry;
-    }
-
-    WifiEntry getDefaultWifiEntry() {
-        if (mConnectedEntry != null && mConnectedEntry.isDefaultNetwork()) {
-            return mConnectedEntry;
-        }
-        return null;
-    }
-
     WifiManager getWifiManager() {
         return mWifiManager;
     }
@@ -683,6 +674,10 @@
                 && serviceState.getState() == serviceState.STATE_IN_SERVICE;
     }
 
+    public boolean isDeviceLocked() {
+        return !mKeyguardStateController.isUnlocked();
+    }
+
     boolean activeNetworkIsCellular() {
         if (mConnectivityManager == null) {
             if (DEBUG) {
@@ -746,7 +741,7 @@
                 final Intent intent = new Intent("com.android.settings.WIFI_DIALOG")
                         .putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey());
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                mActivityStarter.startActivity(intent, true);
+                mActivityStarter.startActivity(intent, false /* dismissShade */);
             } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
                 Toast.makeText(mContext, R.string.wifi_failed_connect_message,
                         Toast.LENGTH_SHORT).show();
@@ -758,20 +753,33 @@
         }
     }
 
-    void scanWifiAccessPoints() {
-        mAccessPointController.scanForAccessPoints();
+    private void scanWifiAccessPoints() {
+        if (mCanConfigWifi) {
+            mAccessPointController.scanForAccessPoints();
+        }
     }
 
     @Override
+    @WorkerThread
     public void onAccessPointsChanged(List<WifiEntry> accessPoints) {
-        if (accessPoints == null) {
+        if (!mCanConfigWifi) {
+            return;
+        }
+
+        if (accessPoints == null || accessPoints.size() == 0) {
+            mConnectedEntry = null;
+            mWifiEntriesCount = 0;
+            if (mCallback != null) {
+                mCallback.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */);
+            }
             return;
         }
 
         boolean hasConnectedWifi = false;
-        mWifiEntry = accessPoints;
-        for (WifiEntry wifiEntry : accessPoints) {
-            if (wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
+        final int accessPointSize = accessPoints.size();
+        for (int i = 0; i < accessPointSize; i++) {
+            WifiEntry wifiEntry = accessPoints.get(i);
+            if (wifiEntry.isDefaultNetwork() && wifiEntry.hasInternetAccess()) {
                 mConnectedEntry = wifiEntry;
                 hasConnectedWifi = true;
                 break;
@@ -781,7 +789,23 @@
             mConnectedEntry = null;
         }
 
-        mCallback.onAccessPointsChanged(mWifiEntry, getDefaultWifiEntry());
+        int count = MAX_WIFI_ENTRY_COUNT;
+        if (hasCarrier()) {
+            count -= 1;
+        }
+        if (hasConnectedWifi) {
+            count -= 1;
+        }
+        final List<WifiEntry> wifiEntries = accessPoints.stream()
+                .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork()
+                        || !wifiEntry.hasInternetAccess()))
+                .limit(count)
+                .collect(Collectors.toList());
+        mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+
+        if (mCallback != null) {
+            mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry);
+        }
     }
 
     @Override
@@ -834,8 +858,17 @@
 
     private class DataConnectivityListener extends ConnectivityManager.NetworkCallback {
         @Override
+        @WorkerThread
         public void onCapabilitiesChanged(@NonNull Network network,
                 @NonNull NetworkCapabilities networkCapabilities) {
+            if (mCanConfigWifi) {
+                for (int transport : networkCapabilities.getTransportTypes()) {
+                    if (transport == NetworkCapabilities.TRANSPORT_WIFI) {
+                        scanWifiAccessPoints();
+                        break;
+                    }
+                }
+            }
             final Network activeNetwork = mConnectivityManager.getActiveNetwork();
             if (activeNetwork != null && activeNetwork.equals(network)) {
                 // update UI
@@ -848,11 +881,6 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)
-                    || action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
-                mCallback.onWifiStateReceived(context, intent);
-            }
-
             if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
                 if (DEBUG) {
                     Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
@@ -908,8 +936,7 @@
 
         void dismissDialog();
 
-        void onAccessPointsChanged(List<WifiEntry> wifiEntryList, WifiEntry connectedEntry);
-
-        void onWifiStateReceived(Context context, Intent intent);
+        void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
+                @Nullable WifiEntry connectedEntry);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index e82e89ef1..11c6980 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -31,17 +31,17 @@
  */
 @SysUISingleton
 class InternetDialogFactory @Inject constructor(
-        @Main private val handler: Handler,
-        private val internetDialogController: InternetDialogController,
-        private val context: Context,
-        private val uiEventLogger: UiEventLogger
+    @Main private val handler: Handler,
+    private val internetDialogController: InternetDialogController,
+    private val context: Context,
+    private val uiEventLogger: UiEventLogger
 ) {
     companion object {
         var internetDialog: InternetDialog? = null
     }
 
     /** Creates a [InternetDialog]. */
-    fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean) {
+    fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) {
         if (internetDialog != null) {
             if (DEBUG) {
                 Log.d(TAG, "InternetDialog is showing, do not create it twice.")
@@ -49,7 +49,7 @@
             return
         } else {
             internetDialog = InternetDialog(context, this, internetDialogController,
-                    canConfigMobileData, aboveStatusBar, uiEventLogger, handler)
+                    canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler)
             internetDialog?.show()
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
new file mode 100644
index 0000000..2ad06c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.user
+
+import android.content.Context
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowInsets
+import android.view.WindowManager
+import com.android.systemui.qs.PseudoGridView
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.R
+
+/**
+ * Dialog for switching users or creating new ones.
+ */
+class UserDialog(
+    context: Context
+) : SystemUIDialog(context, R.style.Theme_SystemUI_Dialog_QSDialog) {
+
+    // create() is no-op after creation
+    private lateinit var _doneButton: View
+    /**
+     * Button with text "Done" in dialog.
+     */
+    val doneButton: View
+        get() {
+            create()
+            return _doneButton
+        }
+
+    private lateinit var _settingsButton: View
+    /**
+     * Button with text "User Settings" in dialog.
+     */
+    val settingsButton: View
+        get() {
+            create()
+            return _settingsButton
+        }
+
+    private lateinit var _grid: PseudoGridView
+    /**
+     * Grid to populate with user avatar from adapter
+     */
+    val grid: ViewGroup
+        get() {
+            create()
+            return _grid
+        }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        window?.apply {
+            setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+            attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
+            attributes.receiveInsetsIgnoringZOrder = true
+            setLayout(
+                    context.resources.getDimensionPixelSize(R.dimen.qs_panel_width),
+                    ViewGroup.LayoutParams.WRAP_CONTENT
+            )
+            setGravity(Gravity.CENTER)
+        }
+        setContentView(R.layout.qs_user_dialog_content)
+
+        _doneButton = requireViewById(R.id.done)
+        _settingsButton = requireViewById(R.id.settings)
+        _grid = requireViewById(R.id.grid)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
new file mode 100644
index 0000000..a5e4ba1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
@@ -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.systemui.qs.user
+
+import android.content.Context
+import android.content.Intent
+import android.provider.Settings
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.tiles.UserDetailView
+import javax.inject.Inject
+import javax.inject.Provider
+
+/**
+ * Controller for [UserDialog].
+ */
+@SysUISingleton
+class UserSwitchDialogController @VisibleForTesting constructor(
+    private val userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>,
+    private val activityStarter: ActivityStarter,
+    private val falsingManager: FalsingManager,
+    private val dialogFactory: (Context) -> UserDialog
+) {
+
+    @Inject
+    constructor(
+        userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>,
+        activityStarter: ActivityStarter,
+        falsingManager: FalsingManager
+    ) : this(
+        userDetailViewAdapterProvider,
+        activityStarter,
+        falsingManager,
+        { UserDialog(it) }
+    )
+
+    companion object {
+        private val USER_SETTINGS_INTENT = Intent(Settings.ACTION_USER_SETTINGS)
+    }
+
+    /**
+     * Show a [UserDialog].
+     *
+     * Populate the dialog with information from and adapter obtained from
+     * [userDetailViewAdapterProvider] and show it as launched from [view].
+     */
+    fun showDialog(view: View) {
+        with(dialogFactory(view.context)) {
+            setShowForAllUsers(true)
+            setCanceledOnTouchOutside(true)
+            create() // Needs to be called before we can retrieve views
+
+            settingsButton.setOnClickListener {
+                if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+                    activityStarter.postStartActivityDismissingKeyguard(USER_SETTINGS_INTENT, 0)
+                }
+                dismiss()
+            }
+            doneButton.setOnClickListener { dismiss() }
+
+            val adapter = userDetailViewAdapterProvider.get()
+            adapter.injectCallback {
+                dismiss()
+            }
+            adapter.linkToViewGroup(grid)
+
+            show()
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index eb72296..4584b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -78,6 +78,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBar;
 import com.android.systemui.navigationbar.NavigationBarController;
@@ -93,6 +94,7 @@
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.CallbackController;
@@ -530,6 +532,7 @@
             Optional<OneHanded> oneHandedOptional,
             BroadcastDispatcher broadcastDispatcher,
             ShellTransitions shellTransitions,
+            ScreenLifecycle screenLifecycle,
             Optional<StartingSurface> startingSurface,
             SmartspaceTransitionController smartspaceTransitionController) {
         super(broadcastDispatcher);
@@ -544,7 +547,7 @@
                 com.android.internal.R.string.config_recentsComponentName));
         mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
-        mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
+        mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
         mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
                 .supportsRoundedCornersOnWindows(mContext.getResources());
         mSysUiState = sysUiState;
@@ -588,6 +591,13 @@
         // Listen for user setup
         startTracking();
 
+        screenLifecycle.addObserver(new ScreenLifecycle.Observer() {
+            @Override
+            public void onScreenTurnedOn() {
+                notifyScreenTurnedOn();
+            }
+        });
+
         // Connect to the service
         updateEnabledState();
         startConnectionToCurrentUser();
@@ -617,18 +627,22 @@
                 mNavBarControllerLazy.get().getDefaultNavigationBar();
         final NavigationBarView navBarView =
                 mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
+        final NotificationPanelViewController panelController =
+                mStatusBarOptionalLazy.get().get().getPanelController();
         if (SysUiState.DEBUG) {
             Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
-                    + " navBarView=" + navBarView);
+                    + " navBarView=" + navBarView + " panelController=" + panelController);
         }
 
         if (navBarFragment != null) {
             navBarFragment.updateSystemUiStateFlags(-1);
         }
         if (navBarView != null) {
-            navBarView.updatePanelSystemUiStateFlags();
             navBarView.updateDisabledSystemUiStateFlags();
         }
+        if (panelController != null) {
+            panelController.updateSystemUiStateFlags();
+        }
         if (mStatusBarWinController != null) {
             mStatusBarWinController.notifyStateChangedCallbacks();
         }
@@ -880,6 +894,21 @@
         }
     }
 
+    /**
+     * Notifies the Launcher that screen turned on and ready to use
+     */
+    public void notifyScreenTurnedOn() {
+        try {
+            if (mOverviewProxy != null) {
+                mOverviewProxy.onScreenTurnedOn();
+            } else {
+                Log.e(TAG_OPS, "Failed to get overview proxy for screen turned on event.");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG_OPS, "Failed to call notifyScreenTurnedOn()", e);
+        }
+    }
+
     void notifyToggleRecentApps() {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
             mConnectionCallbacks.get(i).onToggleRecentApps();
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index 0aa9d4d..5a6f2a2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -27,6 +27,7 @@
 import android.media.MediaRecorder;
 import android.media.projection.MediaProjection;
 import android.util.Log;
+import android.util.MathUtils;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -128,30 +129,64 @@
         mThread = new Thread(() -> {
             short[] bufferInternal = null;
             short[] bufferMic = null;
-            byte[] buffer = null;
+            byte[] buffer = new byte[size];
 
             if (mMic) {
                 bufferInternal = new short[size / 2];
                 bufferMic = new short[size / 2];
-            } else {
-                buffer = new byte[size];
             }
 
+            int readBytes = 0;
+            int readShortsInternal = 0;
+            int offsetShortsInternal = 0;
+            int readShortsMic = 0;
+            int offsetShortsMic = 0;
             while (true) {
-                int readBytes = 0;
-                int readShortsInternal = 0;
-                int readShortsMic = 0;
                 if (mMic) {
-                    readShortsInternal = mAudioRecord.read(bufferInternal, 0,
-                            bufferInternal.length);
-                    readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+                    readShortsInternal = mAudioRecord.read(bufferInternal, offsetShortsInternal,
+                            bufferInternal.length - offsetShortsInternal);
+                    readShortsMic = mAudioRecordMic.read(
+                            bufferMic, offsetShortsMic, bufferMic.length - offsetShortsMic);
+
+                    // if both error, end the recording
+                    if (readShortsInternal < 0 && readShortsMic < 0) {
+                        break;
+                    }
+
+                    // if one has an errors, fill its buffer with zeros and assume it is mute
+                    // with the same size as the other buffer
+                    if (readShortsInternal < 0) {
+                        readShortsInternal = readShortsMic;
+                        offsetShortsInternal = offsetShortsMic;
+                        java.util.Arrays.fill(bufferInternal, (short) 0);
+                    }
+
+                    if (readShortsMic < 0) {
+                        readShortsMic = readShortsInternal;
+                        offsetShortsMic = offsetShortsInternal;
+                        java.util.Arrays.fill(bufferMic, (short) 0);
+                    }
+
+                    // Add offset (previous unmixed values) to the buffer
+                    readShortsInternal += offsetShortsInternal;
+                    readShortsMic += offsetShortsMic;
+
+                    int minShorts = Math.min(readShortsInternal, readShortsMic);
+                    readBytes = minShorts * 2;
 
                     // modify the volume
-                    bufferMic = scaleValues(bufferMic,
-                            readShortsMic, MIC_VOLUME_SCALE);
-                    readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
-                    buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
-                            readShortsMic);
+                    // scale only mixed shorts
+                    scaleValues(bufferMic, minShorts, MIC_VOLUME_SCALE);
+                    // Mix the two buffers
+                    addAndConvertBuffers(bufferInternal, bufferMic, buffer, minShorts);
+
+                    // shift unmixed shorts to the beginning of the buffer
+                    shiftToStart(bufferInternal, minShorts, offsetShortsInternal);
+                    shiftToStart(bufferMic, minShorts, offsetShortsMic);
+
+                    // reset the offset for the next loop
+                    offsetShortsInternal = readShortsInternal - minShorts;
+                    offsetShortsMic = readShortsMic - minShorts;
                 } else {
                     readBytes = mAudioRecord.read(buffer, 0, buffer.length);
                 }
@@ -169,40 +204,31 @@
         });
     }
 
-    private short[] scaleValues(short[] buff, int len, float scale) {
-        for (int i = 0; i < len; i++) {
-            int oldValue = buff[i];
-            int newValue = (int) (buff[i] * scale);
-            if (newValue > Short.MAX_VALUE) {
-                newValue = Short.MAX_VALUE;
-            } else if (newValue < Short.MIN_VALUE) {
-                newValue = Short.MIN_VALUE;
-            }
-            buff[i] = (short) (newValue);
+    /**
+     * moves all bits from start to end to the beginning of the array
+     */
+    private void shiftToStart(short[] target, int start, int end) {
+        for (int i = 0; i  < end - start; i++) {
+            target[i] = target[start + i];
         }
-        return buff;
     }
-    private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
-        int size = Math.max(a1Limit, a2Limit);
-        if (size < 0) return new byte[0];
-        byte[] buff = new byte[size * 2];
-        for (int i = 0; i < size; i++) {
-            int sum;
-            if (i > a1Limit) {
-                sum = a2[i];
-            } else if (i > a2Limit) {
-                sum = a1[i];
-            } else {
-                sum = (int) a1[i] + (int) a2[i];
-            }
 
-            if (sum > Short.MAX_VALUE) sum = Short.MAX_VALUE;
-            if (sum < Short.MIN_VALUE) sum = Short.MIN_VALUE;
-            int byteIndex = i * 2;
-            buff[byteIndex] = (byte) (sum & 0xff);
-            buff[byteIndex + 1] = (byte) ((sum >> 8) & 0xff);
+    private void scaleValues(short[] buff, int len, float scale) {
+        for (int i = 0; i < len; i++) {
+            int newValue = (int) (buff[i] * scale);
+            buff[i] = (short) MathUtils.constrain(newValue, Short.MIN_VALUE, Short.MAX_VALUE);
         }
-        return buff;
+    }
+
+    private void addAndConvertBuffers(short[] src1, short[] src2, byte[] dst, int sizeShorts) {
+        for (int i = 0; i < sizeShorts; i++) {
+            int sum;
+            sum = (short) MathUtils.constrain(
+                    (int) src1[i] + (int) src2[i], Short.MIN_VALUE, Short.MAX_VALUE);
+            int byteIndex = i * 2;
+            dst[byteIndex] = (byte) (sum & 0xff);
+            dst[byteIndex + 1] = (byte) ((sum >> 8) & 0xff);
+        }
     }
 
     private void encode(byte[] buffer, int readBytes) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 0eaef72..31d51f1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -154,6 +154,7 @@
     @Override
     public void onStart() {
         super.onStart();
+        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_STARTED);
 
         if (mPreview.getDrawable() != null) {
             // We already have an image, so no need to try to load again.
@@ -245,6 +246,8 @@
     }
 
     private void onCachedImageLoaded(ImageLoader.Result imageResult) {
+        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED);
+
         BitmapDrawable drawable = new BitmapDrawable(getResources(), imageResult.bitmap);
         mPreview.setImageDrawable(drawable);
         mPreview.setAlpha(1f);
@@ -282,6 +285,8 @@
             finish();
         }
         if (isFinishing()) {
+            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_FINISHED);
+
             if (mScrollCaptureResponse != null) {
                 mScrollCaptureResponse.close();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 16872b0..8def475 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -33,6 +33,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.MainThread;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -261,6 +262,7 @@
     private Bitmap mScreenBitmap;
     private SaveImageInBackgroundTask mSaveInBgTask;
     private boolean mScreenshotTakenInPortrait;
+    private boolean mBlockAttach;
 
     private Animator mScreenshotAnimation;
     private RequestCallback mCurrentRequestCallback;
@@ -559,8 +561,8 @@
             mScreenshotView.reset();
         }
 
-        mScreenshotView.updateOrientation(mWindowManager.getCurrentWindowMetrics()
-                .getWindowInsets().getDisplayCutout());
+        mScreenshotView.updateOrientation(
+                mWindowManager.getCurrentWindowMetrics().getWindowInsets());
 
         mScreenBitmap = screenshot;
 
@@ -594,9 +596,8 @@
                             // Delay scroll capture eval a bit to allow the underlying activity
                             // to set up in the new orientation.
                             mScreenshotHandler.postDelayed(this::requestScrollCapture, 150);
-                            mScreenshotView.updateDisplayCutoutMargins(
-                                    mWindowManager.getCurrentWindowMetrics().getWindowInsets()
-                                            .getDisplayCutout());
+                            mScreenshotView.updateInsets(
+                                    mWindowManager.getCurrentWindowMetrics().getWindowInsets());
                             // screenshot animation calculations won't be valid anymore, so just end
                             if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
                                 mScreenshotAnimation.end();
@@ -660,7 +661,7 @@
                     + mLastScrollCaptureResponse.getWindowTitle() + "]");
 
             final ScrollCaptureResponse response = mLastScrollCaptureResponse;
-            mScreenshotView.showScrollChip(/* onClick */ () -> {
+            mScreenshotView.showScrollChip(response.getPackageName(), /* onClick */ () -> {
                 DisplayMetrics displayMetrics = new DisplayMetrics();
                 getDefaultDisplay().getRealMetrics(displayMetrics);
                 Bitmap newScreenshot = captureScreenshot(
@@ -732,6 +733,7 @@
                     new ViewTreeObserver.OnWindowAttachListener() {
                         @Override
                         public void onWindowAttached() {
+                            mBlockAttach = false;
                             decorView.getViewTreeObserver().removeOnWindowAttachListener(this);
                             action.run();
                         }
@@ -748,14 +750,16 @@
         mWindow.setContentView(contentView);
     }
 
+    @MainThread
     private void attachWindow() {
         View decorView = mWindow.getDecorView();
-        if (decorView.isAttachedToWindow()) {
+        if (decorView.isAttachedToWindow() || mBlockAttach) {
             return;
         }
         if (DEBUG_WINDOW) {
             Log.d(TAG, "attachWindow");
         }
+        mBlockAttach = true;
         mWindowManager.addView(decorView, mWindowLayoutParams);
         decorView.requestApplyInsets();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 5cf0188..169b28c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -71,7 +71,19 @@
     @UiEvent(doc = "User has shared a long screenshot")
     SCREENSHOT_LONG_SCREENSHOT_SHARE(689),
     @UiEvent(doc = "User has sent a long screenshot to the editor")
-    SCREENSHOT_LONG_SCREENSHOT_EDIT(690);
+    SCREENSHOT_LONG_SCREENSHOT_EDIT(690),
+    @UiEvent(doc = "A long screenshot capture has started")
+    SCREENSHOT_LONG_SCREENSHOT_STARTED(880),
+    @UiEvent(doc = "The long screenshot capture failed")
+    SCREENSHOT_LONG_SCREENSHOT_FAILURE(881),
+    @UiEvent(doc = "The long screenshot capture completed successfully")
+    SCREENSHOT_LONG_SCREENSHOT_COMPLETED(882),
+    @UiEvent(doc = "Long screenshot editor activity started")
+    SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_STARTED(889),
+    @UiEvent(doc = "Long screenshot editor activity loaded a previously saved screenshot")
+    SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED(890),
+    @UiEvent(doc = "Long screenshot editor activity finished")
+    SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_FINISHED(891);
 
     private final int mId;
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index e9e62f2..dfb39e3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -118,8 +118,8 @@
     private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
     private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
     private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
-    private static final long SCREENSHOT_DISMISS_Y_DURATION_MS = 350;
-    private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 183;
+    private static final long SCREENSHOT_DISMISS_X_DURATION_MS = 350;
+    private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 350;
     private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
     private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
     private static final float ROUNDED_CORNER_RADIUS = .25f;
@@ -242,19 +242,21 @@
     /**
      * Called to display the scroll action chip when support is detected.
      *
+     * @param packageName the owning package of the window to be captured
      * @param onClick the action to take when the chip is clicked.
      */
-    public void showScrollChip(Runnable onClick) {
+    public void showScrollChip(String packageName, Runnable onClick) {
         if (DEBUG_SCROLL) {
             Log.d(TAG, "Showing Scroll option");
         }
-        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION);
+        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION, 0, packageName);
         mScrollChip.setVisibility(VISIBLE);
         mScrollChip.setOnClickListener((v) -> {
             if (DEBUG_INPUT) {
                 Log.d(TAG, "scroll chip tapped");
             }
-            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED);
+            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED, 0,
+                    packageName);
             onClick.run();
         });
     }
@@ -414,21 +416,30 @@
         mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
     }
 
-    void updateDisplayCutoutMargins(DisplayCutout cutout) {
+    void updateInsets(WindowInsets insets) {
         int orientation = mContext.getResources().getConfiguration().orientation;
         mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
         FrameLayout.LayoutParams p =
                 (FrameLayout.LayoutParams) mScreenshotStatic.getLayoutParams();
+        DisplayCutout cutout = insets.getDisplayCutout();
+        Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
         if (cutout == null) {
-            p.setMargins(0, 0, 0, 0);
+            p.setMargins(0, 0, 0, navBarInsets.bottom);
         } else {
             Insets waterfall = cutout.getWaterfallInsets();
             if (mOrientationPortrait) {
-                p.setMargins(waterfall.left, Math.max(cutout.getSafeInsetTop(), waterfall.top),
-                        waterfall.right, Math.max(cutout.getSafeInsetBottom(), waterfall.bottom));
+                p.setMargins(
+                        waterfall.left,
+                        Math.max(cutout.getSafeInsetTop(), waterfall.top),
+                        waterfall.right,
+                        Math.max(cutout.getSafeInsetBottom(),
+                                Math.max(navBarInsets.bottom, waterfall.bottom)));
             } else {
-                p.setMargins(Math.max(cutout.getSafeInsetLeft(), waterfall.left), waterfall.top,
-                        Math.max(cutout.getSafeInsetRight(), waterfall.right), waterfall.bottom);
+                p.setMargins(
+                        Math.max(cutout.getSafeInsetLeft(), waterfall.left),
+                        waterfall.top,
+                        Math.max(cutout.getSafeInsetRight(), waterfall.right),
+                        Math.max(navBarInsets.bottom, waterfall.bottom));
             }
         }
         mStaticLeftMargin = p.leftMargin;
@@ -436,10 +447,10 @@
         mScreenshotStatic.requestLayout();
     }
 
-    void updateOrientation(DisplayCutout cutout) {
+    void updateOrientation(WindowInsets insets) {
         int orientation = mContext.getResources().getConfiguration().orientation;
         mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
-        updateDisplayCutoutMargins(cutout);
+        updateInsets(insets);
         int screenshotFixedSize =
                 mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
         ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams();
@@ -978,7 +989,6 @@
         mScrollingScrim.setVisibility(View.GONE);
         mScrollablePreview.setVisibility(View.GONE);
         mScreenshotStatic.setTranslationX(0);
-        mScreenshotPreview.setTranslationY(0);
         mScreenshotPreview.setContentDescription(
                 mContext.getResources().getString(R.string.screenshot_preview_description));
         mScreenshotPreview.setOnClickListener(null);
@@ -994,9 +1004,6 @@
         mSmartChips.clear();
         mQuickShareChip = null;
         setAlpha(1);
-        mDismissButton.setTranslationY(0);
-        mActionsContainer.setTranslationY(0);
-        mActionsContainerBackground.setTranslationY(0);
         mScreenshotSelectorView.stop();
     }
 
@@ -1024,22 +1031,19 @@
             setAlpha(1 - animation.getAnimatedFraction());
         });
 
-        ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
-        yAnim.setInterpolator(mAccelerateInterpolator);
-        yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
-        float screenshotStartY = mScreenshotPreview.getTranslationY();
-        float dismissStartY = mDismissButton.getTranslationY();
-        yAnim.addUpdateListener(animation -> {
-            float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
-            mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
-            mScreenshotPreviewBorder.setTranslationY(screenshotStartY + yDelta);
-            mDismissButton.setTranslationY(dismissStartY + yDelta);
-            mActionsContainer.setTranslationY(yDelta);
-            mActionsContainerBackground.setTranslationY(yDelta);
+        ValueAnimator xAnim = ValueAnimator.ofFloat(0, 1);
+        xAnim.setInterpolator(mAccelerateInterpolator);
+        xAnim.setDuration(SCREENSHOT_DISMISS_X_DURATION_MS);
+        float deltaX = mDirectionLTR
+                    ? -1 * (mScreenshotPreviewBorder.getX() + mScreenshotPreviewBorder.getWidth())
+                    : (mDisplayMetrics.widthPixels - mScreenshotPreviewBorder.getX());
+        xAnim.addUpdateListener(animation -> {
+            float currXDelta = MathUtils.lerp(0, deltaX, animation.getAnimatedFraction());
+            mScreenshotStatic.setTranslationX(currXDelta);
         });
 
         AnimatorSet animSet = new AnimatorSet();
-        animSet.play(yAnim).with(alphaAnim);
+        animSet.play(xAnim).with(alphaAnim);
 
         return animSet;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 6dc6874..ef7355a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -28,6 +28,7 @@
 import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
@@ -61,6 +62,7 @@
     private final Context mContext;
     private final Executor mBgExecutor;
     private final ImageTileSet mImageTileSet;
+    private final UiEventLogger mEventLogger;
     private final ScrollCaptureClient mClient;
 
     private Completer<LongScreenshot> mCaptureCompleter;
@@ -69,6 +71,7 @@
     private Session mSession;
     private ListenableFuture<CaptureResult> mTileFuture;
     private ListenableFuture<Void> mEndFuture;
+    private String mWindowOwner;
 
     static class LongScreenshot {
         private final ImageTileSet mImageTileSet;
@@ -135,11 +138,12 @@
 
     @Inject
     ScrollCaptureController(Context context, @Background Executor bgExecutor,
-            ScrollCaptureClient client, ImageTileSet imageTileSet) {
+            ScrollCaptureClient client, ImageTileSet imageTileSet, UiEventLogger logger) {
         mContext = context;
         mBgExecutor = bgExecutor;
         mClient = client;
         mImageTileSet = imageTileSet;
+        mEventLogger = logger;
     }
 
     @VisibleForTesting
@@ -157,6 +161,7 @@
     ListenableFuture<LongScreenshot> run(ScrollCaptureResponse response) {
         return CallbackToFutureAdapter.getFuture(completer -> {
             mCaptureCompleter = completer;
+            mWindowOwner = response.getPackageName();
             mBgExecutor.execute(() -> {
                 float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(),
                         SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT);
@@ -173,11 +178,13 @@
             if (LogConfig.DEBUG_SCROLL) {
                 Log.d(TAG, "got session " + mSession);
             }
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_STARTED, 0, mWindowOwner);
             requestNextTile(0);
         } catch (InterruptedException | ExecutionException e) {
             // Failure to start, propagate to caller
             Log.e(TAG, "session start failed!");
             mCaptureCompleter.setException(e);
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_FAILURE, 0, mWindowOwner);
         }
     }
 
@@ -297,6 +304,11 @@
         if (LogConfig.DEBUG_SCROLL) {
             Log.d(TAG, "finishCapture()");
         }
+        if (mImageTileSet.getHeight() > 0) {
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_COMPLETED, 0, mWindowOwner);
+        } else {
+            mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_FAILURE, 0, mWindowOwner);
+        }
         mEndFuture = mSession.end();
         mEndFuture.addListener(() -> {
             if (LogConfig.DEBUG_SCROLL) {
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 185b8ef..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,8 +46,8 @@
 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;
 
@@ -288,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) {
@@ -464,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/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index dce19cf..cfbe3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -54,22 +54,22 @@
     /**
      * Translates a ratio from 0 to 1 to a blur radius in pixels.
      */
-    fun blurRadiusOfRatio(ratio: Float): Int {
+    fun blurRadiusOfRatio(ratio: Float): Float {
         if (ratio == 0f) {
-            return 0
+            return 0f
         }
-        return MathUtils.lerp(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), ratio).toInt()
+        return MathUtils.lerp(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), ratio)
     }
 
     /**
      * Translates a blur radius in pixels to a ratio between 0 to 1.
      */
-    fun ratioOfBlurRadius(blur: Int): Float {
-        if (blur == 0) {
+    fun ratioOfBlurRadius(blur: Float): Float {
+        if (blur == 0f) {
             return 0f
         }
         return MathUtils.map(minBlurRadius.toFloat(), maxBlurRadius.toFloat(),
-                0f /* maxStart */, 1f /* maxStop */, blur.toFloat())
+                0f /* maxStart */, 1f /* maxStop */, blur)
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 90158c32..aba1a24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -291,8 +291,8 @@
         default void showAuthenticationDialog(PromptInfo promptInfo,
                 IBiometricSysuiReceiver receiver,
                 int[] sensorIds, boolean credentialAllowed,
-                boolean requireConfirmation, int userId, String opPackageName,
-                long operationId, @BiometricMultiSensorMode int multiSensorConfig) {
+                boolean requireConfirmation, int userId, long operationId, String opPackageName,
+                long requestId, @BiometricMultiSensorMode int multiSensorConfig) {
         }
 
         /** @see IStatusBar#onBiometricAuthenticated() */
@@ -845,7 +845,7 @@
     @Override
     public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
             int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
-            int userId, String opPackageName, long operationId,
+            int userId, long operationId, String opPackageName, long requestId,
             @BiometricMultiSensorMode int multiSensorConfig) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
@@ -857,6 +857,7 @@
             args.argi1 = userId;
             args.arg6 = opPackageName;
             args.arg7 = operationId;
+            args.arg8 = requestId;
             args.argi2 = multiSensorConfig;
             mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
                     .sendToTarget();
@@ -1315,8 +1316,9 @@
                                 (boolean) someArgs.arg4 /* credentialAllowed */,
                                 (boolean) someArgs.arg5 /* requireConfirmation */,
                                 someArgs.argi1 /* userId */,
-                                (String) someArgs.arg6 /* opPackageName */,
                                 (long) someArgs.arg7 /* operationId */,
+                                (String) someArgs.arg6 /* opPackageName */,
+                                (long) someArgs.arg8 /* requestId */,
                                 someArgs.argi2 /* multiSensorConfig */);
                     }
                     someArgs.recycle();
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 3890c1a..eb5f82c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -811,24 +811,28 @@
                 mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
             }
         } else if (mKeyguardUpdateMonitor.isScreenOn()) {
-            if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
-                showTransientIndication(mContext.getString(R.string.keyguard_unlock_press),
-                        false /* isError */, true /* hideOnScreenOff */);
-            } else {
-                showTransientIndication(mContext.getString(R.string.keyguard_unlock),
-                        false /* isError */, true /* hideOnScreenOff */);
-            }
+            showTransientIndication(mContext.getString(R.string.keyguard_unlock),
+                    false /* isError */, true /* hideOnScreenOff */);
         }
     }
 
-    private void showTryFingerprintMsg() {
+    private void showTryFingerprintMsg(String a11yString) {
         if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
             // if udfps available, there will always be a tappable affordance to unlock
             // For example, the lock icon
-            showTransientIndication(R.string.keyguard_unlock_press);
+            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);
         }
+
+        // Although we suppress face auth errors visually, we still announce them for a11y
+        if (!TextUtils.isEmpty(a11yString)) {
+            mLockScreenIndicationView.announceForAccessibility(a11yString);
+        }
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -909,7 +913,7 @@
             } else if (mKeyguardUpdateMonitor.isScreenOn()) {
                 if (biometricSourceType == BiometricSourceType.FACE
                         && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
-                    showTryFingerprintMsg();
+                    showTryFingerprintMsg(helpString);
                     return;
                 }
                 showTransientIndication(helpString, false /* isError */, showActionToUnlock);
@@ -929,7 +933,7 @@
                     && shouldSuppressFaceMsgAndShowTryFingerprintMsg()
                     && !mStatusBarKeyguardViewManager.isBouncerShowing()
                     && mKeyguardUpdateMonitor.isScreenOn()) {
-                showTryFingerprintMsg();
+                showTryFingerprintMsg(errString);
                 return;
             }
             if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -938,7 +942,7 @@
                 if (!mStatusBarKeyguardViewManager.isBouncerShowing()
                         && mKeyguardUpdateMonitor.isUdfpsEnrolled()
                         && mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
-                    showTryFingerprintMsg();
+                    showTryFingerprintMsg(errString);
                 } else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
                     mStatusBarKeyguardViewManager.showBouncerMessage(
                             mContext.getResources().getString(R.string.keyguard_unlock_press),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 8780ad8..03d8e7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -12,8 +12,10 @@
 import android.graphics.RadialGradient
 import android.graphics.Shader
 import android.util.AttributeSet
+import android.util.MathUtils.lerp
 import android.view.View
 import com.android.systemui.animation.Interpolators
+import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
 import java.util.function.Consumer
 
 /**
@@ -63,12 +65,12 @@
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
         val ovalWidthIncreaseAmount =
-                LightRevealEffect.getPercentPastThreshold(interpolatedAmount, WIDEN_OVAL_THRESHOLD)
+                getPercentPastThreshold(interpolatedAmount, WIDEN_OVAL_THRESHOLD)
 
         val initialWidthMultiplier = (1f - OVAL_INITIAL_WIDTH_PERCENT) / 2f
 
         with(scrim) {
-            revealGradientEndColorAlpha = 1f - LightRevealEffect.getPercentPastThreshold(
+            revealGradientEndColorAlpha = 1f - getPercentPastThreshold(
                     amount, FADE_END_COLOR_OUT_THRESHOLD)
             setRevealGradientBounds(
                     scrim.width * initialWidthMultiplier +
@@ -90,26 +92,49 @@
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
 
-        // TODO(b/193801466): add alpha reveal in the beginning as well
+        scrim.startColorAlpha =
+            getPercentPastThreshold(1 - interpolatedAmount,
+                threshold = 1 - START_COLOR_REVEAL_PERCENTAGE)
+
         scrim.revealGradientEndColorAlpha =
-            1f - LightRevealEffect.getPercentPastThreshold(interpolatedAmount, threshold = 0.6f)
+            1f - getPercentPastThreshold(interpolatedAmount,
+                threshold = REVEAL_GRADIENT_END_COLOR_ALPHA_START_PERCENTAGE)
+
+        // Start changing gradient bounds later to avoid harsh gradient in the beginning
+        val gradientBoundsAmount = lerp(GRADIENT_START_BOUNDS_PERCENTAGE, 1.0f, interpolatedAmount)
 
         if (isVertical) {
             scrim.setRevealGradientBounds(
-                left = scrim.width / 2 - (scrim.width / 2) * interpolatedAmount,
+                left = scrim.width / 2 - (scrim.width / 2) * gradientBoundsAmount,
                 top = 0f,
-                right = scrim.width / 2 + (scrim.width / 2) * interpolatedAmount,
+                right = scrim.width / 2 + (scrim.width / 2) * gradientBoundsAmount,
                 bottom = scrim.height.toFloat()
             )
         } else {
             scrim.setRevealGradientBounds(
                 left = 0f,
-                top = scrim.height / 2 - (scrim.height / 2) * interpolatedAmount,
+                top = scrim.height / 2 - (scrim.height / 2) * gradientBoundsAmount,
                 right = scrim.width.toFloat(),
-                bottom = scrim.height / 2 + (scrim.height / 2) * interpolatedAmount
+                bottom = scrim.height / 2 + (scrim.height / 2) * gradientBoundsAmount
             )
         }
     }
+
+    private companion object {
+        // From which percentage we should start the gradient reveal width
+        // E.g. if 0 - starts with 0px width, 0.3f - starts with 30% width
+        private const val GRADIENT_START_BOUNDS_PERCENTAGE = 0.3f
+
+        // When to start changing alpha color of the gradient scrim
+        // E.g. if 0.6f - starts fading the gradient away at 60% and becomes completely
+        // transparent at 100%
+        private const val REVEAL_GRADIENT_END_COLOR_ALPHA_START_PERCENTAGE = 0.6f
+
+        // When to finish displaying start color fill that reveals the content
+        // E.g. if 0.3f - the content won't be visible at 0% and it will gradually
+        // reduce the alpha until 30% (at this point the color fill is invisible)
+        private const val START_COLOR_REVEAL_PERCENTAGE = 0.3f
+    }
 }
 
 class CircleReveal(
@@ -125,7 +150,7 @@
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         // reveal amount updates already have an interpolator, so we intentionally use the
         // non-interpolated amount
-        val fadeAmount = LightRevealEffect.getPercentPastThreshold(amount, 0.5f)
+        val fadeAmount = getPercentPastThreshold(amount, 0.5f)
         val radius = startRadius + ((endRadius - startRadius) * amount)
         scrim.revealGradientEndColorAlpha = 1f - fadeAmount
         scrim.setRevealGradientBounds(
@@ -153,8 +178,7 @@
 
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         val interpolatedAmount = Interpolators.FAST_OUT_SLOW_IN_REVERSE.getInterpolation(amount)
-        val fadeAmount =
-                LightRevealEffect.getPercentPastThreshold(interpolatedAmount, 0.5f)
+        val fadeAmount = getPercentPastThreshold(interpolatedAmount, 0.5f)
 
         with(scrim) {
             revealGradientEndColorAlpha = 1f - fadeAmount
@@ -178,7 +202,10 @@
  */
 class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
 
-    lateinit var revealAmountListener: Consumer<Float>
+    /**
+     * Listener that is called if the scrim's opaqueness changes
+     */
+    lateinit var isScrimOpaqueChangedListener: Consumer<Boolean>
 
     /**
      * How much of the underlying views are revealed, in percent. 0 means they will be completely
@@ -190,7 +217,7 @@
                 field = value
 
                 revealEffect.setRevealAmountOnScrim(value, this)
-                revealAmountListener.accept(value)
+                updateScrimOpaque()
                 invalidate()
             }
         }
@@ -213,6 +240,23 @@
     var revealGradientWidth: Float = 0f
     var revealGradientHeight: Float = 0f
 
+    /**
+     * Alpha of the fill that can be used in the beginning of the animation to hide the content.
+     * Normally the gradient bounds are animated from small size so the content is not visible,
+     * but if the start gradient bounds allow to see some content this could be used to make the
+     * reveal smoother. It can help to add fade in effect in the beginning of the animation.
+     * The color of the fill is determined by [revealGradientEndColor].
+     *
+     * 0 - no fill and content is visible, 1 - the content is covered with the start color
+     */
+    var startColorAlpha = 0f
+        set(value) {
+            if (field != value) {
+                field = value
+                invalidate()
+            }
+        }
+
     var revealGradientEndColor: Int = Color.BLACK
         set(value) {
             if (field != value) {
@@ -230,6 +274,31 @@
         }
 
     /**
+     * Is the scrim currently fully opaque
+     */
+    var isScrimOpaque = false
+        private set(value) {
+            if (field != value) {
+                field = value
+                isScrimOpaqueChangedListener.accept(field)
+            }
+        }
+
+    private fun updateScrimOpaque() {
+        isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE
+    }
+
+    override fun setAlpha(alpha: Float) {
+        super.setAlpha(alpha)
+        updateScrimOpaque()
+    }
+
+    override fun setVisibility(visibility: Int) {
+        super.setVisibility(visibility)
+        updateScrimOpaque()
+    }
+
+    /**
      * Paint used to draw a transparent-to-white radial gradient. This will be scaled and translated
      * via local matrix in [onDraw] so we never need to construct a new shader.
      */
@@ -281,6 +350,10 @@
             return
         }
 
+        if (startColorAlpha > 0f) {
+            canvas.drawColor(updateColorAlpha(revealGradientEndColor, startColorAlpha))
+        }
+
         with(shaderGradientMatrix) {
             setScale(revealGradientWidth, revealGradientHeight, 0f, 0f)
             postTranslate(revealGradientCenter.x, revealGradientCenter.y)
@@ -294,11 +367,15 @@
 
     private fun setPaintColorFilter() {
         gradientPaint.colorFilter = PorterDuffColorFilter(
-                Color.argb(
-                        (revealGradientEndColorAlpha * 255).toInt(),
-                        Color.red(revealGradientEndColor),
-                        Color.green(revealGradientEndColor),
-                        Color.blue(revealGradientEndColor)),
-                PorterDuff.Mode.MULTIPLY)
+            updateColorAlpha(revealGradientEndColor, revealGradientEndColorAlpha),
+            PorterDuff.Mode.MULTIPLY)
     }
+
+    private fun updateColorAlpha(color: Int, alpha: Float): Int =
+        Color.argb(
+            (alpha * 255).toInt(),
+            Color.red(color),
+            Color.green(color),
+            Color.blue(color)
+        )
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index db553e4..e845804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -68,7 +68,7 @@
         private const val VELOCITY_SCALE = 100f
         private const val MAX_VELOCITY = 3000f
         private const val MIN_VELOCITY = -MAX_VELOCITY
-        private const val INTERACTION_BLUR_FRACTION = 0.4f
+        private const val INTERACTION_BLUR_FRACTION = 0.8f
         private const val ANIMATION_BLUR_FRACTION = 1f - INTERACTION_BLUR_FRACTION
         private const val TAG = "DepthController"
     }
@@ -92,8 +92,6 @@
     // Only for dumpsys
     private var lastAppliedBlur = 0
 
-    @VisibleForTesting
-    var shadeSpring = DepthAnimation()
     var shadeAnimation = DepthAnimation()
 
     @VisibleForTesting
@@ -101,12 +99,16 @@
     var brightnessMirrorVisible: Boolean = false
         set(value) {
             field = value
-            brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f)
+            brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f).toInt()
                 else 0)
         }
 
     var qsPanelExpansion = 0f
         set(value) {
+            if (value.isNaN()) {
+                Log.w(TAG, "Invalid qs expansion")
+                return
+            }
             if (field == value) return
             field = value
             scheduleUpdate()
@@ -134,15 +136,13 @@
             field = value
             scheduleUpdate()
 
-            if (shadeSpring.radius == 0 && shadeAnimation.radius == 0) {
+            if (shadeExpansion == 0f && shadeAnimation.radius == 0f) {
                 return
             }
             // Do not remove blurs when we're re-enabling them
             if (!value) {
                 return
             }
-            shadeSpring.animateTo(0)
-            shadeSpring.finishIfRunning()
 
             shadeAnimation.animateTo(0)
             shadeAnimation.finishIfRunning()
@@ -161,7 +161,7 @@
     /**
      * Blur radius of the wake-up animation on this frame.
      */
-    private var wakeAndUnlockBlurRadius = 0
+    private var wakeAndUnlockBlurRadius = 0f
         set(value) {
             if (field == value) return
             field = value
@@ -174,25 +174,31 @@
     @VisibleForTesting
     val updateBlurCallback = Choreographer.FrameCallback {
         updateScheduled = false
-        val normalizedBlurRadius = MathUtils.constrain(shadeAnimation.radius,
-                blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
-        var combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
-                normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
-        combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion))
+        val animationRadius = MathUtils.constrain(shadeAnimation.radius,
+                blurUtils.minBlurRadius.toFloat(), blurUtils.maxBlurRadius.toFloat())
+        val expansionRadius = blurUtils.blurRadiusOfRatio(
+                Interpolators.getNotificationScrimAlpha(
+                        if (shouldApplyShadeBlur()) shadeExpansion else 0f, false))
+        var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION +
+                animationRadius * ANIMATION_BLUR_FRACTION)
+        val qsExpandedRatio = Interpolators.getNotificationScrimAlpha(qsPanelExpansion,
+                false /* notification */) * shadeExpansion
+        combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
-        var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
+        var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
 
         if (blursDisabledForAppLaunch) {
             shadeRadius = 0f
         }
 
+        var zoomOut = MathUtils.saturate(blurUtils.ratioOfBlurRadius(shadeRadius))
         var blur = shadeRadius.toInt()
 
         // Make blur be 0 if it is necessary to stop blur effect.
         if (scrimsVisible) {
             blur = 0
+            zoomOut = 0f
         }
-        val zoomOut = blurUtils.ratioOfBlurRadius(blur)
 
         if (!blurUtils.supportsBlursOnWindows()) {
             blur = 0
@@ -265,12 +271,11 @@
         override fun onStateChanged(newState: Int) {
             updateShadeAnimationBlur(
                     shadeExpansion, prevTracking, prevShadeVelocity, prevShadeDirection)
-            updateShadeBlur()
+            scheduleUpdate()
         }
 
         override fun onDozingChanged(isDozing: Boolean) {
             if (isDozing) {
-                shadeSpring.finishIfRunning()
                 shadeAnimation.finishIfRunning()
                 brightnessMirrorSpring.finishIfRunning()
             }
@@ -335,7 +340,7 @@
         prevTracking = tracking
         prevTimestamp = timestamp
 
-        updateShadeBlur()
+        scheduleUpdate()
     }
 
     private fun updateShadeAnimationBlur(
@@ -398,15 +403,7 @@
         }
 
         shadeAnimation.setStartVelocity(velocity)
-        shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized))
-    }
-
-    private fun updateShadeBlur() {
-        var newBlur = 0
-        if (shouldApplyShadeBlur()) {
-            newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion)
-        }
-        shadeSpring.animateTo(newBlur)
+        shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized).toInt())
     }
 
     private fun scheduleUpdate(viewToBlur: View? = null) {
@@ -432,7 +429,8 @@
         IndentingPrintWriter(pw, "  ").let {
             it.println("StatusBarWindowBlurController:")
             it.increaseIndent()
-            it.println("shadeRadius: ${shadeSpring.radius}")
+            it.println("shadeExpansion: $shadeExpansion")
+            it.println("shouldApplyShaeBlur: ${shouldApplyShadeBlur()}")
             it.println("shadeAnimation: ${shadeAnimation.radius}")
             it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
             it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
@@ -451,7 +449,7 @@
         /**
          * Blur radius visible on the UI, in pixels.
          */
-        var radius = 0
+        var radius = 0f
 
         /**
          * Depth ratio of the current blur radius.
@@ -472,12 +470,12 @@
         private var springAnimation = SpringAnimation(this, object :
                 FloatPropertyCompat<DepthAnimation>("blurRadius") {
             override fun setValue(rect: DepthAnimation?, value: Float) {
-                radius = value.toInt()
+                radius = value
                 scheduleUpdate(view)
             }
 
             override fun getValue(rect: DepthAnimation?): Float {
-                return radius.toFloat()
+                return radius
             }
         })
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index f0d779c..4adf2bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import android.graphics.Region;
 import android.view.ViewGroup;
 
 import androidx.annotation.Nullable;
@@ -158,6 +159,9 @@
     /** Sets the state of whether the notification shade is touchable or not. */
     default void setNotTouchable(boolean notTouchable) {}
 
+    /** Sets the region where touch is excluded from the parent window. */
+    default void setTouchExclusionRegion(Region region) {}
+
     /** Sets a {@link OtherwisedCollapsedListener}. */
     default void setStateListener(OtherwisedCollapsedListener listener) {}
 
@@ -182,10 +186,10 @@
     default void setFaceAuthDisplayBrightness(float brightness) {}
 
     /**
-     * How much {@link LightRevealScrim} obscures the UI.
-     * @param amount 0 when opaque, 1 when not transparent
+     * If {@link LightRevealScrim} obscures the UI.
+     * @param opaque if the scrim is opaque
      */
-    default void setLightRevealScrimAmount(float amount) {}
+    default void setLightRevealScrimOpaque(boolean opaque) {}
 
     /**
      * Custom listener to pipe data back to plugins about whether or not the status bar would be
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index cc7a4f8..4a6d7e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -15,46 +15,18 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionInfo;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.WirelessUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.demomode.DemoModeCommandReceiver;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.List;
 
 /** Shows the operator name */
-public class OperatorNameView extends TextView implements DemoModeCommandReceiver, DarkReceiver,
-        SignalCallback, Tunable {
-
-    private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
-
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+public class OperatorNameView extends TextView {
     private boolean mDemoMode;
 
-    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onRefreshCarrierInfo() {
-            updateText();
-        }
-    };
-
     public OperatorNameView(Context context) {
         this(context, null);
     }
@@ -67,62 +39,14 @@
         super(context, attrs, defStyle);
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
-        mKeyguardUpdateMonitor.registerCallback(mCallback);
-        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
-        Dependency.get(NetworkController.class).addCallback(this);
-        Dependency.get(TunerService.class).addTunable(this, KEY_SHOW_OPERATOR_NAME);
+    void setDemoMode(boolean demoMode) {
+        mDemoMode = demoMode;
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mKeyguardUpdateMonitor.removeCallback(mCallback);
-        Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
-        Dependency.get(NetworkController.class).removeCallback(this);
-        Dependency.get(TunerService.class).removeTunable(this);
-    }
-
-    @Override
-    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
-        setTextColor(DarkIconDispatcher.getTint(area, this, tint));
-    }
-
-    @Override
-    public void setIsAirplaneMode(IconState icon) {
-        update();
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        update();
-    }
-
-    @Override
-    public void dispatchDemoCommand(String command, Bundle args) {
-        setText(args.getString("name"));
-    }
-
-    @Override
-    public void onDemoModeStarted() {
-        mDemoMode = true;
-    }
-
-    @Override
-    public void onDemoModeFinished() {
-        mDemoMode = false;
-        update();
-    }
-
-    private void update() {
-        boolean showOperatorName = Dependency.get(TunerService.class)
-                .getValue(KEY_SHOW_OPERATOR_NAME, 1) != 0;
+    void update(boolean showOperatorName, boolean hasMobile,
+            List<OperatorNameViewController.SubInfo> subs) {
         setVisibility(showOperatorName ? VISIBLE : GONE);
 
-        boolean hasMobile = mContext.getSystemService(TelephonyManager.class).isDataCapable();
         boolean airplaneMode = WirelessUtils.isAirplaneModeOn(mContext);
         if (!hasMobile || airplaneMode) {
             setText(null);
@@ -131,22 +55,19 @@
         }
 
         if (!mDemoMode) {
-            updateText();
+            updateText(subs);
         }
     }
 
-    private void updateText() {
+    void updateText(List<OperatorNameViewController.SubInfo> subs) {
         CharSequence displayText = null;
-        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
         final int N = subs.size();
         for (int i = 0; i < N; i++) {
-            int subId = subs.get(i).getSubscriptionId();
-            int simState = mKeyguardUpdateMonitor.getSimState(subId);
+            OperatorNameViewController.SubInfo subInfo = subs.get(i);
             CharSequence carrierName = subs.get(i).getCarrierName();
-            if (!TextUtils.isEmpty(carrierName) && simState == TelephonyManager.SIM_STATE_READY) {
-                ServiceState ss = mKeyguardUpdateMonitor.getServiceState(subId);
-                if (ss != null && ss.getState() == ServiceState.STATE_IN_SERVICE) {
-                    displayText = carrierName;
+            if (!TextUtils.isEmpty(carrierName) && subInfo.simReady()) {
+                if (subInfo.stateInService()) {
+                    displayText = subInfo.getCarrierName();
                     break;
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
new file mode 100644
index 0000000..e49f48f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
@@ -0,0 +1,201 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+import android.view.View;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.ViewController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/** Controller for {@link OperatorNameView}. */
+public class OperatorNameViewController extends ViewController<OperatorNameView> {
+    private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
+
+    private final DarkIconDispatcher mDarkIconDispatcher;
+    private final NetworkController mNetworkController;
+    private final TunerService mTunerService;
+    private final TelephonyManager mTelephonyManager;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+    private OperatorNameViewController(OperatorNameView view,
+            DarkIconDispatcher darkIconDispatcher,
+            NetworkController networkController,
+            TunerService tunerService,
+            TelephonyManager telephonyManager,
+            KeyguardUpdateMonitor keyguardUpdateMonitor) {
+        super(view);
+        mDarkIconDispatcher = darkIconDispatcher;
+        mNetworkController = networkController;
+        mTunerService = tunerService;
+        mTelephonyManager = telephonyManager;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mDarkIconDispatcher.addDarkReceiver(mDarkReceiver);
+        mNetworkController.addCallback(mSignalCallback);
+        mTunerService.addTunable(mTunable, KEY_SHOW_OPERATOR_NAME);
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mDarkIconDispatcher.removeDarkReceiver(mDarkReceiver);
+        mNetworkController.removeCallback(mSignalCallback);
+        mTunerService.removeTunable(mTunable);
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+    }
+
+    private void update() {
+        mView.update(mTunerService.getValue(KEY_SHOW_OPERATOR_NAME, 1) != 0,
+                mTelephonyManager.isDataCapable(), getSubInfos());
+    }
+
+    private List<SubInfo> getSubInfos() {
+        List<SubInfo> result = new ArrayList<>();
+        List<SubscriptionInfo> subscritionInfos =
+                mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
+
+        for (SubscriptionInfo subscriptionInfo : subscritionInfos) {
+            int subId = subscriptionInfo.getSubscriptionId();
+            result.add(new SubInfo(
+                    subscriptionInfo.getCarrierName(),
+                    mKeyguardUpdateMonitor.getSimState(subId),
+                    mKeyguardUpdateMonitor.getServiceState(subId)));
+        }
+
+        return result;
+    }
+
+    /** Factory for constructing an {@link OperatorNameViewController}. */
+    public static class Factory {
+        private final DarkIconDispatcher mDarkIconDispatcher;
+        private final NetworkController mNetworkController;
+        private final TunerService mTunerService;
+        private final TelephonyManager mTelephonyManager;
+        private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+        @Inject
+        public Factory(DarkIconDispatcher darkIconDispatcher, NetworkController networkController,
+                TunerService tunerService, TelephonyManager telephonyManager,
+                KeyguardUpdateMonitor keyguardUpdateMonitor) {
+            mDarkIconDispatcher = darkIconDispatcher;
+            mNetworkController = networkController;
+            mTunerService = tunerService;
+            mTelephonyManager = telephonyManager;
+            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        }
+
+        /** Create an {@link OperatorNameViewController}. */
+        public OperatorNameViewController create(OperatorNameView view) {
+            return new OperatorNameViewController(view, mDarkIconDispatcher, mNetworkController,
+                    mTunerService, mTelephonyManager, mKeyguardUpdateMonitor);
+        }
+    }
+
+    /**
+     * Needed because of how {@link CollapsedStatusBarFragment} works.
+     *
+     * Ideally this can be done internally.
+     **/
+    public View getView() {
+        return mView;
+    }
+
+    private final DarkIconDispatcher.DarkReceiver mDarkReceiver =
+            (area, darkIntensity, tint) ->
+                    mView.setTextColor(DarkIconDispatcher.getTint(area, mView, tint));
+
+    private final NetworkController.SignalCallback mSignalCallback =
+            new NetworkController.SignalCallback() {
+        @Override
+        public void setIsAirplaneMode(NetworkController.IconState icon) {
+            update();
+        }
+    };
+
+    private final TunerService.Tunable mTunable = (key, newValue) -> update();
+
+
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onRefreshCarrierInfo() {
+            mView.updateText(getSubInfos());
+        }
+    };
+
+    // TODO: do we even register this anywhere?
+    private final DemoModeCommandReceiver mDemoModeCommandReceiver = new DemoModeCommandReceiver() {
+        @Override
+        public void onDemoModeStarted() {
+            mView.setDemoMode(true);
+        }
+
+        @Override
+        public void onDemoModeFinished() {
+            mView.setDemoMode(false);
+            update();
+        }
+
+        @Override
+        public void dispatchDemoCommand(String command, Bundle args) {
+            mView.setText(args.getString("name"));
+        }
+    };
+
+    static class SubInfo {
+        private final CharSequence mCarrierName;
+        private final int mSimState;
+        private final ServiceState mServiceState;
+
+        private SubInfo(CharSequence carrierName,
+                int simState, ServiceState serviceState) {
+            mCarrierName = carrierName;
+            mSimState = simState;
+            mServiceState = serviceState;
+        }
+
+        boolean simReady() {
+            return mSimState == TelephonyManager.SIM_STATE_READY;
+        }
+
+        CharSequence getCarrierName() {
+            return mCarrierName;
+        }
+
+        boolean stateInService() {
+            return mServiceState != null
+                    && mServiceState.getState() == ServiceState.STATE_IN_SERVICE;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java
deleted file mode 100644
index e4ae560..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java
+++ /dev/null
@@ -1,139 +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.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
-import com.android.systemui.statusbar.phone.StatusBarWindowView;
-import com.android.systemui.util.InjectionInflationController;
-
-import javax.inject.Inject;
-
-/**
- * Creates a single instance of super_status_bar and super_notification_shade that can be shared
- * across various system ui objects.
- */
-@SysUISingleton
-public class SuperStatusBarViewFactory {
-
-    private final Context mContext;
-    private final InjectionInflationController mInjectionInflationController;
-    private final NotificationShelfComponent.Builder mNotificationShelfComponentBuilder;
-
-    private NotificationShadeWindowView mNotificationShadeWindowView;
-    private StatusBarWindowView mStatusBarWindowView;
-    private NotificationShelfController mNotificationShelfController;
-
-    @Inject
-    public SuperStatusBarViewFactory(Context context,
-            InjectionInflationController injectionInflationController,
-            NotificationShelfComponent.Builder notificationShelfComponentBuilder) {
-        mContext = context;
-        mInjectionInflationController = injectionInflationController;
-        mNotificationShelfComponentBuilder = notificationShelfComponentBuilder;
-    }
-
-    /**
-     * Gets the inflated {@link NotificationShadeWindowView} from
-     * {@link R.layout#super_notification_shade}.
-     * Returns a cached instance, if it has already been inflated.
-     */
-    public NotificationShadeWindowView getNotificationShadeWindowView() {
-        if (mNotificationShadeWindowView != null) {
-            return mNotificationShadeWindowView;
-        }
-
-        mNotificationShadeWindowView = (NotificationShadeWindowView)
-                mInjectionInflationController.injectable(
-                LayoutInflater.from(mContext)).inflate(R.layout.super_notification_shade,
-                /* root= */ null);
-        if (mNotificationShadeWindowView == null) {
-            throw new IllegalStateException(
-                    "R.layout.super_notification_shade could not be properly inflated");
-        }
-
-        return mNotificationShadeWindowView;
-    }
-
-    /**
-     * Gets the inflated {@link StatusBarWindowView} from {@link R.layout#super_status_bar}.
-     * Returns a cached instance, if it has already been inflated.
-     */
-    public StatusBarWindowView getStatusBarWindowView() {
-        if (mStatusBarWindowView != null) {
-            return mStatusBarWindowView;
-        }
-
-        mStatusBarWindowView =
-                (StatusBarWindowView) mInjectionInflationController.injectable(
-                LayoutInflater.from(mContext)).inflate(R.layout.super_status_bar,
-                /* root= */ null);
-        if (mStatusBarWindowView == null) {
-            throw new IllegalStateException(
-                    "R.layout.super_status_bar could not be properly inflated");
-        }
-        return mStatusBarWindowView;
-    }
-
-    /**
-     * Gets the inflated {@link NotificationShelf} from
-     * {@link R.layout#status_bar_notification_shelf}.
-     * Returns a cached instance, if it has already been inflated.
-     *
-     * @param container the expected container to hold the {@link NotificationShelf}. The view
-     *                  isn't immediately attached, but the layout params of this view is used
-     *                  during inflation.
-     */
-    public NotificationShelfController getNotificationShelfController(ViewGroup container) {
-        if (mNotificationShelfController != null) {
-            return mNotificationShelfController;
-        }
-
-        NotificationShelf view = (NotificationShelf) LayoutInflater.from(mContext)
-                .inflate(R.layout.status_bar_notification_shelf, container, /* attachToRoot= */
-                        false);
-
-        if (view == null) {
-            throw new IllegalStateException(
-                    "R.layout.status_bar_notification_shelf could not be properly inflated");
-        }
-
-        NotificationShelfComponent component = mNotificationShelfComponentBuilder
-                .notificationShelf(view)
-                .build();
-        mNotificationShelfController = component.getNotificationShelfController();
-        mNotificationShelfController.init();
-
-        return mNotificationShelfController;
-    }
-
-    public NotificationPanelView getNotificationPanelView() {
-        NotificationShadeWindowView notificationShadeWindowView = getNotificationShadeWindowView();
-        if (notificationShadeWindowView == null) {
-            return null;
-        }
-
-        return mNotificationShadeWindowView.findViewById(R.id.notification_panel);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
index 4a467ce..d01fc93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
@@ -104,7 +104,7 @@
         // the active effect area. Values here should be kept in sync with the
         // animation implementation in the ripple shader.
         val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
-                (1 - rippleShader.progress)) * radius * 1.5f
+                (1 - rippleShader.progress)) * radius * 2
         canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index c1f0578..1000788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -498,7 +498,12 @@
         }
 
         if (state.designatedCorner != currentViewState.designatedCorner) {
+            currentViewState.designatedCorner?.contentDescription = null
+            state.designatedCorner?.contentDescription = state.contentDescription
+
             updateDesignatedCorner(state.designatedCorner, state.shouldShowDot())
+        } else if (state.contentDescription != currentViewState.contentDescription) {
+            state.designatedCorner?.contentDescription = state.contentDescription
         }
 
         val shouldShow = state.shouldShowDot()
@@ -515,9 +520,13 @@
 
     private val systemStatusAnimationCallback: SystemStatusAnimationCallback =
             object : SystemStatusAnimationCallback {
-        override fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? {
+        override fun onSystemStatusAnimationTransitionToPersistentDot(
+            contentDescr: String?
+        ): Animator? {
             synchronized(lock) {
-                nextViewState = nextViewState.copy(systemPrivacyEventIsActive = true)
+                nextViewState = nextViewState.copy(
+                        systemPrivacyEventIsActive = true,
+                        contentDescription = contentDescr)
             }
 
             return null
@@ -621,7 +630,9 @@
     val rotation: Int = 0,
     val height: Int = 0,
     val cornerIndex: Int = -1,
-    val designatedCorner: View? = null
+    val designatedCorner: View? = null,
+
+    val contentDescription: String? = null
 ) {
     fun shouldShowDot(): Boolean {
         return systemPrivacyEventIsActive && !shadeExpanded && !qsExpanded
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index 539020d..d4d84c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -34,6 +34,7 @@
     // Whether or not to show an animation for this event
     val showAnimation: Boolean
     val viewCreator: (context: Context) -> View
+    var contentDescription: String?
 
     // Update this event with values from another event.
     fun updateFromEvent(other: StatusEvent?) {
@@ -50,6 +51,7 @@
     override val priority = 50
     override val forceVisible = false
     override val showAnimation = true
+    override var contentDescription: String? = ""
 
     override val viewCreator: (context: Context) -> View = { context ->
         val iv = ImageView(context)
@@ -62,7 +64,9 @@
         return javaClass.simpleName
     }
 }
+
 class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
+    override var contentDescription: String? = null
     override val priority = 100
     override val forceVisible = true
     var privacyItems: List<PrivacyItem> = listOf()
@@ -72,6 +76,7 @@
         val v = LayoutInflater.from(context)
                 .inflate(R.layout.ongoing_privacy_chip, null) as OngoingPrivacyChip
         v.privacyList = privacyItems
+        v.contentDescription = contentDescription
         privacyChip = v
         v
     }
@@ -81,7 +86,9 @@
     }
 
     override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
-        return other is PrivacyEvent && other.privacyItems != privacyItems
+        return other is PrivacyEvent &&
+                (other.privacyItems != privacyItems ||
+                other.contentDescription != contentDescription)
     }
 
     override fun updateFromEvent(other: StatusEvent?) {
@@ -90,6 +97,9 @@
         }
 
         privacyItems = other.privacyItems
+        contentDescription = other.contentDescription
+
+        privacyChip?.contentDescription = other.contentDescription
         privacyChip?.privacyList = other.privacyItems
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index b861c1d..589446f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -24,22 +24,18 @@
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.widget.FrameLayout
-
 import com.android.systemui.R
-import com.android.systemui.statusbar.SuperStatusBarViewFactory
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
 import com.android.systemui.statusbar.phone.StatusBarWindowController
 import com.android.systemui.statusbar.phone.StatusBarWindowView
-
 import javax.inject.Inject
 
 /**
- * //TODO: this _probably_ doesn't control a window anymore
- * Controls the window for system event animations.
+ * Controls the view for system event animations.
  */
 class SystemEventChipAnimationController @Inject constructor(
     private val context: Context,
-    private val statusBarViewFactory: SuperStatusBarViewFactory,
+    private val statusBarWindowView: StatusBarWindowView,
     private val statusBarWindowController: StatusBarWindowController,
     private val locationPublisher: StatusBarLocationPublisher
 ) : SystemStatusChipAnimationCallback {
@@ -52,7 +48,6 @@
 
     private lateinit var animationWindowView: FrameLayout
     private lateinit var animationDotView: View
-    private lateinit var statusBarWindowView: StatusBarWindowView
     private var currentAnimatedView: View? = null
 
     // TODO: move to dagger
@@ -126,7 +121,6 @@
 
     private fun init() {
         initialized = true
-        statusBarWindowView = statusBarViewFactory.statusBarWindowView
         animationWindowView = LayoutInflater.from(context)
                 .inflate(R.layout.system_event_animation_window, null) as FrameLayout
         animationDotView = animationWindowView.findViewById(R.id.dot_view)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
index ba50659..04f7492 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
@@ -16,9 +16,12 @@
 
 package com.android.systemui.statusbar.events
 
+import android.content.Context
 import android.provider.DeviceConfig
 import android.provider.DeviceConfig.NAMESPACE_PRIVACY
+import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.privacy.PrivacyChipBuilder
 import com.android.systemui.privacy.PrivacyItem
 import com.android.systemui.privacy.PrivacyItemController
 import com.android.systemui.statusbar.policy.BatteryController
@@ -33,7 +36,8 @@
 class SystemEventCoordinator @Inject constructor(
     private val systemClock: SystemClock,
     private val batteryController: BatteryController,
-    private val privacyController: PrivacyItemController
+    private val privacyController: PrivacyItemController,
+    private val context: Context
 ) {
     private lateinit var scheduler: SystemStatusAnimationScheduler
 
@@ -66,6 +70,11 @@
     fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) {
         val event = PrivacyEvent(showAnimation)
         event.privacyItems = privacyStateListener.currentPrivacyItems
+        event.contentDescription = {
+            val items = PrivacyChipBuilder(context, event.privacyItems).joinTypes()
+            context.getString(
+                    R.string.ongoing_privacy_chip_content_multiple_apps, items)
+        }()
         scheduler.onStatusEvent(event)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index f30010c..dcf8e73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -100,14 +100,21 @@
 
         // Don't deal with threading for now (no need let's be honest)
         Assert.isMainThread()
-        if (event.priority > scheduledEvent?.priority ?: -1 ||
-            scheduledEvent?.shouldUpdateFromEvent(event) == true) {
+        if ((event.priority > scheduledEvent?.priority ?: -1) &&
+                animationState != ANIMATING_OUT &&
+                (animationState != SHOWING_PERSISTENT_DOT && event.forceVisible)) {
+            // events can only be scheduled if a higher priority or no other event is in progress
             if (DEBUG) {
                 Log.d(TAG, "scheduling event $event")
             }
-            if (event.showAnimation) {
-                scheduleEvent(event)
-            } else if (event.forceVisible) {
+
+            scheduleEvent(event)
+        } else if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
+            if (DEBUG) {
+                Log.d(TAG, "updating current event from: $event")
+            }
+            scheduledEvent?.updateFromEvent(event)
+            if (event.forceVisible) {
                 hasPersistentDot = true
                 notifyTransitionToPersistentDot()
             }
@@ -142,24 +149,19 @@
      * Clear the scheduled event (if any) and schedule a new one
      */
     private fun scheduleEvent(event: StatusEvent) {
-        if (animationState == ANIMATING_OUT ||
-            (animationState == SHOWING_PERSISTENT_DOT && event.forceVisible)) {
-            // do not schedule an event or change the current one
-            return
-        }
+        scheduledEvent = event
 
-        // If we are showing the chip, possibly update the current event, rather than replacing
-        if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
-            scheduledEvent?.updateFromEvent(event)
-            return
-        } else {
-            scheduledEvent = event
-        }
-
-        if (scheduledEvent!!.forceVisible) {
+        if (event.forceVisible) {
             hasPersistentDot = true
         }
 
+        // If animations are turned off, we'll transition directly to the dot
+        if (!event.showAnimation && event.forceVisible) {
+            notifyTransitionToPersistentDot()
+            scheduledEvent = null
+            return
+        }
+
         // Schedule the animation to start after a debounce period
         cancelExecutionRunnable = executor.executeDelayed({
             cancelExecutionRunnable = null
@@ -218,7 +220,7 @@
 
     private fun notifyTransitionToPersistentDot(): Animator? {
         val anims: List<Animator> = listeners.mapNotNull {
-            it.onSystemStatusAnimationTransitionToPersistentDot()
+            it.onSystemStatusAnimationTransitionToPersistentDot(scheduledEvent?.contentDescription)
         }
         if (anims.isNotEmpty()) {
             val aSet = AnimatorSet()
@@ -346,7 +348,10 @@
     @JvmDefault fun onSystemChromeAnimationEnd() {}
 
     // Best method name, change my mind
-    @JvmDefault fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? { return null }
+    @JvmDefault
+    fun onSystemStatusAnimationTransitionToPersistentDot(contentDescription: String?): Animator? {
+        return null
+    }
     @JvmDefault fun onHidePersistentDot(): Animator? { return null }
 }
 
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 fdbe728..f2060b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -31,8 +31,6 @@
 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
@@ -46,21 +44,14 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.settings.UserTracker
 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
  */
@@ -81,15 +72,10 @@
     @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
 
@@ -97,60 +83,12 @@
     private var showSensitiveContentForManagedUser = false
     private var managedUserHandle: UserHandle? = null
 
-    private var isAod = false
-    private var isSplitShade = false
-
-    fun isSmartspaceEnabled(): Boolean {
+    fun isEnabled(): 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.
@@ -158,7 +96,7 @@
     fun buildAndConnectView(parent: ViewGroup): View {
         execution.assertIsMainThread()
 
-        if (!isSmartspaceEnabled()) {
+        if (!isEnabled()) {
             throw RuntimeException("Cannot build view when not enabled")
         }
 
@@ -244,6 +182,7 @@
         userTracker.removeCallback(userTrackerCallback)
         contentResolver.unregisterContentObserver(settingsObserver)
         configurationController.removeCallback(configChangeListener)
+        statusBarStateController.removeCallback(statusBarStateListener)
         session = null
 
         plugin?.onTargetsAvailable(emptyList())
@@ -259,13 +198,6 @@
         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)
@@ -301,23 +233,6 @@
             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/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index a0ef1b6..e26fa04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -28,8 +28,6 @@
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
 
-import static java.util.Objects.requireNonNull;
-
 import android.annotation.MainThread;
 import android.annotation.Nullable;
 import android.util.ArrayMap;
@@ -344,14 +342,8 @@
         mPipelineState.incrementTo(STATE_GROUP_STABILIZING);
         stabilizeGroupingNotifs(mNotifList);
 
-        // Step 5: Sort
-        // Assign each top-level entry a section, then sort the list by section and then within
-        // section by our list of custom comparators
-        dispatchOnBeforeSort(mReadOnlyNotifList);
-        mPipelineState.incrementTo(STATE_SORTING);
-        sortList();
 
-        // Step 6: Filter out entries after pre-group filtering, grouping, promoting and sorting
+        // Step 5: Filter out entries after pre-group filtering, grouping and promoting
         // Now filters can see grouping information to determine whether to filter or not.
         dispatchOnBeforeFinalizeFilter(mReadOnlyNotifList);
         mPipelineState.incrementTo(STATE_FINALIZE_FILTERING);
@@ -359,6 +351,13 @@
         applyNewNotifList();
         pruneIncompleteGroups(mNotifList);
 
+        // Step 6: Sort
+        // Assign each top-level entry a section, then sort the list by section and then within
+        // section by our list of custom comparators
+        dispatchOnBeforeSort(mReadOnlyNotifList);
+        mPipelineState.incrementTo(STATE_SORTING);
+        sortList();
+
         // Step 7: Lock in our group structure and log anything that's changed since the last run
         mPipelineState.incrementTo(STATE_FINALIZING);
         logChanges();
@@ -837,8 +836,8 @@
     private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
 
         int cmp = Integer.compare(
-                requireNonNull(o1.getSection()).getIndex(),
-                requireNonNull(o2.getSection()).getIndex());
+                o1.getSectionIndex(),
+                o2.getSectionIndex());
 
         if (cmp == 0) {
             for (int i = 0; i < mNotifComparators.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
new file mode 100644
index 0000000..369e52f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
@@ -0,0 +1,70 @@
+/*
+ * 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.collection.coordinator;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.communal.CommunalStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import javax.inject.Inject;
+
+/**
+ * {@link CommunalCoordinator} prevents notifications from showing on the keyguard when the communal
+ * view is present.
+ */
+public class CommunalCoordinator implements Coordinator {
+    final CommunalStateController mCommunalStateController;
+    final NotificationEntryManager mNotificationEntryManager;
+    final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+
+    @Inject
+    public CommunalCoordinator(NotificationEntryManager notificationEntryManager,
+            NotificationLockscreenUserManager notificationLockscreenUserManager,
+            CommunalStateController communalStateController) {
+        mNotificationEntryManager = notificationEntryManager;
+        mNotificationLockscreenUserManager = notificationLockscreenUserManager;
+        mCommunalStateController = communalStateController;
+    }
+
+    final NotifFilter mFilter = new NotifFilter("CommunalCoordinator") {
+        @Override
+        public boolean shouldFilterOut(@NonNull NotificationEntry entry, long now) {
+            return mCommunalStateController.getCommunalViewShowing();
+        }
+    };
+
+    final CommunalStateController.Callback mStateCallback = new CommunalStateController.Callback() {
+        @Override
+        public void onCommunalViewShowingChanged() {
+            mFilter.invalidateList();
+            mNotificationEntryManager.updateNotifications("Communal mode state changed");
+        }
+    };
+
+    @Override
+    public void attach(@NonNull NotifPipeline pipeline) {
+        pipeline.addPreGroupFilter(mFilter);
+        mCommunalStateController.addCallback(mStateCallback);
+        mNotificationLockscreenUserManager.addKeyguardNotificationSuppressor(
+                entry -> mCommunalStateController.getCommunalViewShowing());
+    }
+}
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 25b2019..47bc444 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
@@ -61,7 +61,8 @@
             PreparationCoordinator preparationCoordinator,
             MediaCoordinator mediaCoordinator,
             SmartspaceDedupingCoordinator smartspaceDedupingCoordinator,
-            VisualStabilityCoordinator visualStabilityCoordinator) {
+            VisualStabilityCoordinator visualStabilityCoordinator,
+            CommunalCoordinator communalCoordinator) {
         dumpManager.registerDumpable(TAG, this);
 
         mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
@@ -74,6 +75,7 @@
         mCoordinators.add(conversationCoordinator);
         mCoordinators.add(mediaCoordinator);
         mCoordinators.add(visualStabilityCoordinator);
+        mCoordinators.add(communalCoordinator);
 
         if (featureFlags.isSmartspaceDedupingEnabled()) {
             mCoordinators.add(smartspaceDedupingCoordinator);
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 168e086..a98531f 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
@@ -100,7 +100,8 @@
         mNotifCollection.attach(mGroupCoalescer);
         mGroupCoalescer.attach(notificationService);
 
-        Log.d(TAG, "Notif pipeline initialized");
+        Log.d(TAG, "Notif pipeline initialized."
+                + " rendering=" + mFeatureFlags.isNewNotifPipelineRenderingEnabled());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index 798bfe7..027ac0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -82,8 +82,8 @@
     public static final int STATE_GROUPING = 4;
     public static final int STATE_TRANSFORMING = 5;
     public static final int STATE_GROUP_STABILIZING = 6;
-    public static final int STATE_SORTING = 7;
-    public static final int STATE_FINALIZE_FILTERING = 8;
+    public static final int STATE_FINALIZE_FILTERING = 7;
+    public static final int STATE_SORTING = 8;
     public static final int STATE_FINALIZING = 9;
 
     @IntDef(prefix = { "STATE_" }, value = {
@@ -94,8 +94,8 @@
             STATE_GROUPING,
             STATE_TRANSFORMING,
             STATE_GROUP_STABILIZING,
-            STATE_SORTING,
             STATE_FINALIZE_FILTERING,
+            STATE_SORTING,
             STATE_FINALIZING,
     })
     @Retention(RetentionPolicy.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
index 727ce20..289dacb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
@@ -78,7 +78,7 @@
 }
 
 private fun treeSpecToStrHelper(tree: NodeSpec, sb: StringBuilder, indent: String) {
-    sb.append("${indent}ns{${tree.controller.nodeLabel}")
+    sb.append("${indent}{${tree.controller.nodeLabel}}\n")
     if (tree.children.isNotEmpty()) {
         val childIndent = "$indent  "
         for (child in tree.children) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
new file mode 100644
index 0000000..9b8ac72
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.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.systemui.statusbar.notification.collection.render
+
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+
+/**
+ * Converts a notif list (the output of the ShadeListBuilder) into a NodeSpec, an abstract
+ * representation of which views should be present in the shade. This spec will later be consumed
+ * by the ViewDiffer, which will add and remove views until the shade matches the spec. Up until
+ * this point, the pipeline has dealt with pure data representations of notifications (in the
+ * form of NotificationEntries). In this step, NotificationEntries finally become associated with
+ * the views that will represent them. In addition, we add in any non-notification views that also
+ * need to present in the shade, notably the section headers.
+ */
+class NodeSpecBuilder(
+    private val viewBarn: NotifViewBarn
+) {
+    fun buildNodeSpec(
+        rootController: NodeController,
+        notifList: List<ListEntry>
+    ): NodeSpec {
+        val root = NodeSpecImpl(null, rootController)
+        var currentSection: NotifSection? = null
+        val prevSections = mutableSetOf<NotifSection?>()
+
+        for (entry in notifList) {
+            val section = entry.section!!
+
+            if (prevSections.contains(section)) {
+                throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
+            }
+
+            // If this notif begins a new section, first add the section's header view
+            if (section != currentSection) {
+                section.headerController?.let { headerController ->
+                    root.children.add(NodeSpecImpl(root, headerController))
+                }
+                prevSections.add(currentSection)
+                currentSection = section
+            }
+
+            // Finally, add the actual notif node!
+            root.children.add(buildNotifNode(root, entry))
+        }
+
+        return root
+    }
+
+    private fun buildNotifNode(parent: NodeSpec, entry: ListEntry): NodeSpec = when (entry) {
+        is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
+        is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
+                .apply { entry.children.forEach { children.add(buildNotifNode(this, it)) } }
+        else -> throw RuntimeException("Unexpected entry: $entry")
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
index 79bc3d7..c79f59b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
@@ -19,18 +19,16 @@
 import android.view.textclassifier.Log
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.notification.collection.ListEntry
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController
 import javax.inject.Inject
 
 /**
- * The ViewBarn is just a map from [ListEntry] to an instance of an
- * [ExpandableNotificationRowController].
+ * The ViewBarn is just a map from [ListEntry] to an instance of a [NodeController].
  */
 @SysUISingleton
 class NotifViewBarn @Inject constructor() {
-    private val rowMap = mutableMapOf<String, ExpandableNotificationRowController>()
+    private val rowMap = mutableMapOf<String, NodeController>()
 
-    fun requireView(forEntry: ListEntry): ExpandableNotificationRowController {
+    fun requireView(forEntry: ListEntry): NodeController {
         if (DEBUG) {
             Log.d(TAG, "requireView: $forEntry.key")
         }
@@ -42,7 +40,7 @@
         return li
     }
 
-    fun registerViewForEntry(entry: ListEntry, controller: ExpandableNotificationRowController) {
+    fun registerViewForEntry(entry: ListEntry, controller: NodeController) {
         if (DEBUG) {
             Log.d(TAG, "registerViewForEntry: $entry.key")
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index c1a63e9..a2c7aa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -18,9 +18,7 @@
 
 import android.content.Context
 import android.view.View
-import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.ListEntry
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.NotificationIconAreaController
@@ -34,42 +32,21 @@
     context: Context,
     listContainer: NotificationListContainer,
     logger: ShadeViewDifferLogger,
-    private val viewBarn: NotifViewBarn,
+    viewBarn: NotifViewBarn,
     private val notificationIconAreaController: NotificationIconAreaController
 ) {
     // We pass a shim view here because the listContainer may not actually have a view associated
     // with it and the differ never actually cares about the root node's view.
     private val rootController = RootNodeController(listContainer, View(context))
+    private val specBuilder = NodeSpecBuilder(viewBarn)
     private val viewDiffer = ShadeViewDiffer(rootController, logger)
 
     fun attach(listBuilder: ShadeListBuilder) =
             listBuilder.setOnRenderListListener(::onNewNotifTree)
 
-    private fun onNewNotifTree(tree: List<ListEntry>) = viewDiffer.applySpec(buildTree(tree))
-
-    private fun buildTree(notifList: List<ListEntry>): NodeSpec {
-        val root = NodeSpecImpl(null, rootController).apply {
-            // Insert first section header, if present
-            notifList.firstOrNull()?.section?.headerController?.let {
-                children.add(NodeSpecImpl(this, it))
-            }
-            notifList.asSequence().zipWithNext().forEach { (prev, entry) ->
-                // Insert new header if the section has changed between two entries
-                entry.section.takeIf { it != prev.section }?.headerController?.let {
-                    children.add(NodeSpecImpl(this, it))
-                }
-                children.add(buildNotifNode(entry, this))
-            }
-        }
+    private fun onNewNotifTree(notifList: List<ListEntry>) {
+        viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
         notificationIconAreaController.updateNotificationIcons(notifList)
-        return root
-    }
-
-    private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): NodeSpec = when (entry) {
-        is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
-        is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
-                .apply { entry.children.forEach { children.add(buildNotifNode(it, this)) } }
-        else -> throw RuntimeException("Unexpected entry: $entry")
     }
 }
 
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 7a71ee1..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;
@@ -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/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 9bba7ef..1cc1dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -280,7 +280,8 @@
 
     @VisibleForTesting
     fun launchSettings(sender: View) {
-        onSettingsClickListener?.onClick(sender, null, appUid!!)
+        val channel = if (providedChannels.size == 1) providedChannels[0] else null
+        onSettingsClickListener?.onClick(sender, channel, appUid!!)
     }
 
     private fun initDialog() {
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/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 86c90c7..9eb95c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -28,15 +27,12 @@
 import com.android.systemui.statusbar.notification.stack.ViewState;
 
 public class FooterView extends StackScrollerDecorView {
-    private final int mClearAllTopPadding;
     private FooterViewButton mDismissButton;
     private FooterViewButton mManageButton;
     private boolean mShowHistory;
 
     public FooterView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mClearAllTopPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.clear_all_padding_top);
     }
 
     @Override
@@ -55,11 +51,6 @@
         mManageButton = findViewById(R.id.manage_text);
     }
 
-    public void setTextColor(@ColorInt int color) {
-        mManageButton.setTextColor(color);
-        mDismissButton.setTextColor(color);
-    }
-
     public void setManageButtonClickListener(OnClickListener listener) {
         mManageButton.setOnClickListener(listener);
     }
@@ -95,21 +86,25 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        int textColor = getResources().getColor(R.color.notif_pill_text);
-        Resources.Theme theme = getContext().getTheme();
-        mDismissButton.setBackground(
-                getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
-        mDismissButton.setTextColor(textColor);
-        mManageButton.setBackground(
-                getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
-        mManageButton = findViewById(R.id.manage_text);
+        updateColors();
         mDismissButton.setText(R.string.clear_all_notifications_text);
-        mManageButton.setTextColor(textColor);
         mDismissButton.setContentDescription(
                 mContext.getString(R.string.accessibility_clear_all));
         showHistory(mShowHistory);
     }
 
+    /**
+     * Update the text and background colors for the current color palette and night mode setting.
+     */
+    public void updateColors() {
+        Resources.Theme theme = mContext.getTheme();
+        int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+        mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+        mDismissButton.setTextColor(textColor);
+        mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+        mManageButton.setTextColor(textColor);
+    }
+
     @Override
     public ExpandableViewState createExpandableViewState() {
         return new FooterViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index dba3401..9c755e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -85,23 +85,26 @@
     }
 
     /**
-     * Set the content of this view to be visible in an animated way.
-     *
-     * @param contentVisible True if the content should be visible or false if it should be hidden.
+     * @param visible True if we should animate contents visible
      */
-    public void setContentVisible(boolean contentVisible) {
-        setContentVisible(contentVisible, true /* animate */);
+    public void setContentVisible(boolean visible) {
+        setContentVisible(visible, true /* animate */, null /* runAfter */);
     }
+
     /**
-     * Set the content of this view to be visible.
-     * @param contentVisible True if the content should be visible or false if it should be hidden.
-     * @param animate Should an animation be performed.
+     * @param visible True if the contents should be visible
+     * @param animate True if we should fade to new visibility
+     * @param runAfter Runnable to run after visibility updates
      */
-    private void setContentVisible(boolean contentVisible, boolean animate) {
-        if (mContentVisible != contentVisible) {
+    public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) {
+        if (mContentVisible != visible) {
             mContentAnimating = animate;
-            mContentVisible = contentVisible;
-            setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable);
+            mContentVisible = visible;
+            Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> {
+                mContentVisibilityEndRunnable.run();
+                runAfter.run();
+            };
+            setViewVisible(mContent, visible, animate, endRunnable);
         }
 
         if (!mContentAnimating) {
@@ -113,6 +116,10 @@
         return mContentVisible;
     }
 
+    public void setVisible(boolean nowVisible, boolean animate) {
+        setVisible(nowVisible, animate, null);
+    }
+
     /**
      * Make this view visible. If {@code false} is passed, the view will fade out it's content
      * and set the view Visibility to GONE. If only the content should be changed
@@ -121,7 +128,7 @@
      * @param nowVisible should the view be visible
      * @param animate should the change be animated.
      */
-    public void setVisible(boolean nowVisible, boolean animate) {
+    public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) {
         if (mIsVisible != nowVisible) {
             mIsVisible = nowVisible;
             if (animate) {
@@ -132,10 +139,10 @@
                 } else {
                     setWillBeGone(true);
                 }
-                setContentVisible(nowVisible, true /* animate */);
+                setContentVisible(nowVisible, true /* animate */, runAfter);
             } else {
                 setVisibility(nowVisible ? VISIBLE : GONE);
-                setContentVisible(nowVisible, false /* animate */);
+                setContentVisible(nowVisible, false /* animate */, runAfter);
                 setWillBeGone(false);
                 notifyHeightChanged(false /* needsAnimation */);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 23aefd9..135b7df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -24,7 +24,6 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
 
 import java.util.HashSet;
 
@@ -40,27 +39,25 @@
     private final ExpandableView[] mLastInSectionViews;
     private final ExpandableView[] mTmpFirstInSectionViews;
     private final ExpandableView[] mTmpLastInSectionViews;
-    private final KeyguardBypassController mBypassController;
     private boolean mExpanded;
     private HashSet<ExpandableView> mAnimatedChildren;
     private Runnable mRoundingChangedCallback;
     private ExpandableNotificationRow mTrackedHeadsUp;
     private float mAppearFraction;
+    private boolean mRoundForPulsingViews;
+    private boolean mIsDismissAllInProgress;
 
     private ExpandableView mSwipedView = null;
     private ExpandableView mViewBeforeSwipedView = null;
     private ExpandableView mViewAfterSwipedView = null;
 
     @Inject
-    NotificationRoundnessManager(
-            KeyguardBypassController keyguardBypassController,
-            NotificationSectionsFeatureManager sectionsFeatureManager) {
+    NotificationRoundnessManager(NotificationSectionsFeatureManager sectionsFeatureManager) {
         int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
         mFirstInSectionViews = new ExpandableView[numberOfSections];
         mLastInSectionViews = new ExpandableView[numberOfSections];
         mTmpFirstInSectionViews = new ExpandableView[numberOfSections];
         mTmpLastInSectionViews = new ExpandableView[numberOfSections];
-        mBypassController = keyguardBypassController;
     }
 
     public void updateView(ExpandableView view, boolean animate) {
@@ -85,8 +82,8 @@
             return false;
         }
 
-        final float topRoundness = getRoundness(view, true /* top */);
-        final float bottomRoundness = getRoundness(view, false /* top */);
+        final float topRoundness = getRoundnessFraction(view, true /* top */);
+        final float bottomRoundness = getRoundnessFraction(view, false /* top */);
 
         final boolean topChanged = view.setTopRoundness(topRoundness, animate);
         final boolean bottomChanged = view.setBottomRoundness(bottomRoundness, animate);
@@ -131,7 +128,7 @@
         ExpandableView oldViewBefore = mViewBeforeSwipedView;
         mViewBeforeSwipedView = viewBefore;
         if (oldViewBefore != null) {
-            final float bottomRoundness = getRoundness(oldViewBefore, false /* top */);
+            final float bottomRoundness = getRoundnessFraction(oldViewBefore, false /* top */);
             oldViewBefore.setBottomRoundness(bottomRoundness,  animate);
         }
         if (viewBefore != null) {
@@ -141,8 +138,8 @@
         ExpandableView oldSwipedview = mSwipedView;
         mSwipedView = viewSwiped;
         if (oldSwipedview != null) {
-            final float bottomRoundness = getRoundness(oldSwipedview, false /* top */);
-            final float topRoundness = getRoundness(oldSwipedview, true /* top */);
+            final float bottomRoundness = getRoundnessFraction(oldSwipedview, false /* top */);
+            final float topRoundness = getRoundnessFraction(oldSwipedview, true /* top */);
             oldSwipedview.setTopRoundness(topRoundness, animate);
             oldSwipedview.setBottomRoundness(bottomRoundness, animate);
         }
@@ -154,7 +151,7 @@
         ExpandableView oldViewAfter = mViewAfterSwipedView;
         mViewAfterSwipedView = viewAfter;
         if (oldViewAfter != null) {
-            final float topRoundness = getRoundness(oldViewAfter, true /* top */);
+            final float topRoundness = getRoundnessFraction(oldViewAfter, true /* top */);
             oldViewAfter.setTopRoundness(topRoundness, animate);
         }
         if (viewAfter != null) {
@@ -162,7 +159,11 @@
         }
     }
 
-    private float getRoundness(ExpandableView view, boolean top) {
+    void setDismissAllInProgress(boolean isClearingAll) {
+        mIsDismissAllInProgress = isClearingAll;
+    }
+
+    private float getRoundnessFraction(ExpandableView view, boolean top) {
         if (view == null) {
             return 0f;
         }
@@ -171,6 +172,11 @@
                 || view == mViewAfterSwipedView) {
             return 1f;
         }
+        if (view instanceof ExpandableNotificationRow
+                && ((ExpandableNotificationRow) view).canViewBeDismissed()
+                && mIsDismissAllInProgress) {
+            return 1.0f;
+        }
         if ((view.isPinned()
                 || (view.isHeadsUpAnimatingAway()) && !mExpanded)) {
             return 1.0f;
@@ -186,7 +192,7 @@
             // rounded.
             return MathUtils.saturate(1.0f - mAppearFraction);
         }
-        if (view.showingPulsing() && !mBypassController.getBypassEnabled()) {
+        if (view.showingPulsing() && mRoundForPulsingViews) {
             return 1.0f;
         }
         final Resources resources = view.getResources();
@@ -289,4 +295,8 @@
             updateView(previous, true /* animate */);
         }
     }
+
+    public void setShouldRoundPulsingViews(boolean shouldRoundPulsingViews) {
+        mRoundForPulsingViews = shouldRoundPulsingViews;
+    }
 }
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 880e558..3d72ae7 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
@@ -139,6 +139,10 @@
     private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean(
             "persist.debug.nssl.dismiss", false /* default */);
 
+    // Delay in milli-seconds before shade closes for clear all.
+    private final int DELAY_BEFORE_SHADE_CLOSE = 200;
+    private boolean mShadeNeedsToClose = false;
+
     private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
     private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f;
     private static final float RUBBER_BAND_FACTOR_ON_PANEL_EXPAND = 0.21f;
@@ -253,7 +257,6 @@
     protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
     private boolean mDismissAllInProgress;
-    private boolean mFadeNotificationsOnDismiss;
     private FooterDismissListener mFooterDismissListener;
     private boolean mFlingAfterUpEvent;
 
@@ -1205,7 +1208,7 @@
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private void clampScrollPosition() {
         int scrollRange = getScrollRange();
-        if (scrollRange < mOwnScrollY) {
+        if (scrollRange < mOwnScrollY && !mAmbientState.isDismissAllInProgress()) {
             boolean animateStackY = false;
             if (scrollRange < getScrollAmountToScrollBoundary()
                     && mAnimateStackYForContentHeightChange) {
@@ -1721,6 +1724,11 @@
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
+        if (child instanceof SectionHeaderView) {
+             ((StackScrollerDecorView) child).setContentVisible(
+                     false /* visible */, true /* animate */, endRunnable);
+             return;
+        }
         mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
                 true /* isDismissAll */);
     }
@@ -4062,6 +4070,18 @@
         runAnimationFinishedRunnables();
         clearTransient();
         clearHeadsUpDisappearRunning();
+
+        if (mAmbientState.isDismissAllInProgress()) {
+            setDismissAllInProgress(false);
+            if (mShadeNeedsToClose) {
+                mShadeNeedsToClose = false;
+                postDelayed(
+                        () -> {
+                            mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+                        },
+                        DELAY_BEFORE_SHADE_CLOSE /* delayMillis */);
+            }
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4243,7 +4263,7 @@
         final @ColorInt int textColor =
                 Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
         mSectionsManager.setHeaderForegroundColor(textColor);
-        mFooterView.setTextColor(textColor);
+        mFooterView.updateColors();
         mEmptyShadeView.setTextColor(textColor);
     }
 
@@ -4430,6 +4450,7 @@
     public void setDismissAllInProgress(boolean dismissAllInProgress) {
         mDismissAllInProgress = dismissAllInProgress;
         mAmbientState.setDismissAllInProgress(dismissAllInProgress);
+        mController.getNoticationRoundessManager().setDismissAllInProgress(dismissAllInProgress);
         handleDismissAllClipping();
     }
 
@@ -4973,64 +4994,129 @@
         mHeadsUpAppearanceController = headsUpAppearanceController;
     }
 
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    @VisibleForTesting
-    void clearNotifications(@SelectedRows int selection, boolean closeShade) {
-        // animate-swipe all dismissable notifications, then animate the shade closed
-        int numChildren = getChildCount();
+    private boolean isVisible(View child) {
+        boolean hasClipBounds = child.getClipBounds(mTmpRect);
+        return child.getVisibility() == View.VISIBLE
+                && (!hasClipBounds || mTmpRect.height() > 0);
+    }
 
-        final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
-        final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
-        for (int i = 0; i < numChildren; i++) {
-            final View child = getChildAt(i);
-            if (child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                boolean parentVisible = false;
-                boolean hasClipBounds = child.getClipBounds(mTmpRect);
-                if (includeChildInDismissAll(row, selection)) {
-                    viewsToRemove.add(row);
-                    if (child.getVisibility() == View.VISIBLE
-                            && (!hasClipBounds || mTmpRect.height() > 0)) {
-                        viewsToHide.add(child);
-                        parentVisible = true;
-                    }
-                } else if (child.getVisibility() == View.VISIBLE
-                        && (!hasClipBounds || mTmpRect.height() > 0)) {
-                    parentVisible = true;
-                }
-                List<ExpandableNotificationRow> children = row.getAttachedChildren();
-                if (children != null) {
-                    for (ExpandableNotificationRow childRow : children) {
-                        if (includeChildInDismissAll(row, selection)) {
-                            viewsToRemove.add(childRow);
-                            if (parentVisible && row.areChildrenExpanded()) {
-                                hasClipBounds = childRow.getClipBounds(mTmpRect);
-                                if (childRow.getVisibility() == View.VISIBLE
-                                        && (!hasClipBounds || mTmpRect.height() > 0)) {
-                                    viewsToHide.add(childRow);
-                                }
-                            }
+    private boolean shouldHideParent(View view, @SelectedRows int selection) {
+        final boolean silentSectionWillBeGone =
+                !mController.hasNotifications(ROWS_GENTLE, false /* clearable */);
+
+        // The only SectionHeaderView we have is the silent section header.
+        if (view instanceof SectionHeaderView && silentSectionWillBeGone) {
+            return true;
+        }
+        if (view instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            if (isVisible(row) && includeChildInDismissAll(row, selection)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isChildrenVisible(ExpandableNotificationRow parent) {
+        List<ExpandableNotificationRow> children = parent.getAttachedChildren();
+        return isVisible(parent)
+                && children != null
+                && parent.areChildrenExpanded();
+    }
+
+    // Similar to #getRowsToDismissInBackend, but filters for visible views.
+    private ArrayList<View> getVisibleViewsToAnimateAway(@SelectedRows int selection) {
+        final int viewCount = getChildCount();
+        final ArrayList<View> viewsToHide = new ArrayList<>(viewCount);
+
+        for (int i = 0; i < viewCount; i++) {
+            final View view = getChildAt(i);
+
+            if (shouldHideParent(view, selection)) {
+                viewsToHide.add(view);
+            }
+            if (view instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+
+                if (isChildrenVisible(parent)) {
+                    for (ExpandableNotificationRow child : parent.getAttachedChildren()) {
+                        if (isVisible(child) && includeChildInDismissAll(child, selection)) {
+                            viewsToHide.add(child);
                         }
                     }
                 }
             }
         }
+        return viewsToHide;
+    }
 
+    private ArrayList<ExpandableNotificationRow> getRowsToDismissInBackend(
+            @SelectedRows int selection) {
+        final int childCount = getChildCount();
+        final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(childCount);
+
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (!(view instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+            if (includeChildInDismissAll(parent, selection)) {
+                viewsToRemove.add(parent);
+            }
+            List<ExpandableNotificationRow> children = parent.getAttachedChildren();
+            if (isVisible(parent) && children != null) {
+                for (ExpandableNotificationRow child : children) {
+                    if (includeChildInDismissAll(parent, selection)) {
+                        viewsToRemove.add(child);
+                    }
+                }
+            }
+        }
+        return viewsToRemove;
+    }
+
+    /**
+     * Collects a list of visible rows, and animates them away in a staggered fashion as if they
+     * were dismissed. Notifications are dismissed in the backend via onDismissAllAnimationsEnd.
+     */
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    @VisibleForTesting
+    void clearNotifications(@SelectedRows int selection, boolean closeShade) {
+        // Animate-swipe all dismissable notifications, then animate the shade closed
+        final ArrayList<View> viewsToAnimateAway = getVisibleViewsToAnimateAway(selection);
+        final ArrayList<ExpandableNotificationRow> rowsToDismissInBackend =
+                getRowsToDismissInBackend(selection);
         if (mDismissListener != null) {
             mDismissListener.onDismiss(selection);
         }
-
-        if (viewsToRemove.isEmpty()) {
-            if (closeShade && mShadeController != null) {
-                mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
-            }
+        final Runnable dismissInBackend = () -> {
+            onDismissAllAnimationsEnd(rowsToDismissInBackend, selection);
+        };
+        if (viewsToAnimateAway.isEmpty()) {
+            dismissInBackend.run();
             return;
         }
+        // Disable normal animations
+        setDismissAllInProgress(true);
+        mShadeNeedsToClose = closeShade;
 
-        performDismissAllAnimations(
-                viewsToHide,
-                closeShade,
-                () -> onDismissAllAnimationsEnd(viewsToRemove, selection));
+        // Decrease the delay for every row we animate to give the sense of
+        // accelerating the swipes
+        final int rowDelayDecrement = 5;
+        int currentDelay = 60;
+        int totalDelay = 0;
+        final int numItems = viewsToAnimateAway.size();
+        for (int i = numItems - 1; i >= 0; i--) {
+            View view = viewsToAnimateAway.get(i);
+            Runnable endRunnable = null;
+            if (i == 0) {
+                endRunnable = dismissInBackend;
+            }
+            dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE);
+            currentDelay = Math.max(30, currentDelay - rowDelayDecrement);
+            totalDelay += currentDelay;
+        }
     }
 
     private boolean includeChildInDismissAll(
@@ -5039,63 +5125,6 @@
         return canChildBeDismissed(row) && matchesSelection(row, selection);
     }
 
-    /**
-     * Given a list of rows, animates them away in a staggered fashion as if they were dismissed.
-     * Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete
-     * handler.
-     *
-     * @param hideAnimatedList List of rows to animated away. Should only be views that are
-     *                         currently visible, or else the stagger will look funky.
-     * @param closeShade Whether to close the shade after the stagger animation completes.
-     * @param onAnimationComplete Called after the entire animation completes (including the shade
-     *                            closing if appropriate). The rows must be dismissed for real here.
-     */
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void performDismissAllAnimations(
-            final ArrayList<View> hideAnimatedList,
-            final boolean closeShade,
-            final Runnable onAnimationComplete) {
-
-        final Runnable onSlideAwayAnimationComplete = () -> {
-            if (closeShade) {
-                mShadeController.addPostCollapseAction(() -> {
-                    setDismissAllInProgress(false);
-                    onAnimationComplete.run();
-                });
-                mShadeController.animateCollapsePanels(
-                        CommandQueue.FLAG_EXCLUDE_NONE);
-            } else {
-                setDismissAllInProgress(false);
-                onAnimationComplete.run();
-            }
-        };
-
-        if (hideAnimatedList.isEmpty()) {
-            onSlideAwayAnimationComplete.run();
-            return;
-        }
-
-        // let's disable our normal animations
-        setDismissAllInProgress(true);
-
-        // Decrease the delay for every row we animate to give the sense of
-        // accelerating the swipes
-        int rowDelayDecrement = 10;
-        int currentDelay = 140;
-        int totalDelay = 180;
-        int numItems = hideAnimatedList.size();
-        for (int i = numItems - 1; i >= 0; i--) {
-            View view = hideAnimatedList.get(i);
-            Runnable endRunnable = null;
-            if (i == 0) {
-                endRunnable = onSlideAwayAnimationComplete;
-            }
-            dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE);
-            currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
-            totalDelay += currentDelay;
-        }
-    }
-
     /** Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked. */
     public void setManageButtonClickListener(@Nullable OnClickListener listener) {
         mManageButtonClickListener = listener;
@@ -5114,6 +5143,7 @@
                 mFooterDismissListener.onDismiss();
             }
             clearNotifications(ROWS_ALL, true /* closeShade */);
+            footerView.setSecondaryVisible(false /* visible */, true /* animate */);
         });
         setFooterView(footerView);
     }
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 a865c3a..f1ae3da 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
@@ -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);
@@ -691,6 +698,11 @@
         });
         mView.setShadeController(mShadeController);
 
+        mKeyguardBypassController.registerOnBypassStateChangedListener(
+                isEnabled -> mNotificationRoundnessManager.setShouldRoundPulsingViews(!isEnabled));
+        mNotificationRoundnessManager.setShouldRoundPulsingViews(
+                !mKeyguardBypassController.getBypassEnabled());
+
         if (mFgFeatureController.isForegroundServiceDismissalEnabled()) {
             mView.initializeForegroundServiceSection(
                     (ForegroundServiceDungeonView) mFgServicesSectionController.createView(
@@ -1145,6 +1157,10 @@
                 mZenModeController.areNotificationsHiddenInShade());
     }
 
+    public boolean areNotificationsHiddenInShade() {
+        return mZenModeController.areNotificationsHiddenInShade();
+    }
+
     public boolean isShowingEmptyShadeView() {
         return mShowEmptyShadeView;
     }
@@ -1193,6 +1209,10 @@
      * Return whether there are any clearable notifications
      */
     public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
+        return hasNotifications(selection, true /* clearable */);
+    }
+
+    public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) {
         if (mDynamicPrivacyController.isInLockedDownShade()) {
             return false;
         }
@@ -1203,8 +1223,11 @@
                 continue;
             }
             final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            if (row.canViewBeDismissed() &&
-                    NotificationStackScrollLayout.matchesSelection(row, selection)) {
+            final boolean matchClearable =
+                    isClearable ? row.canViewBeDismissed() : !row.canViewBeDismissed();
+            final boolean inSection =
+                    NotificationStackScrollLayout.matchesSelection(row, selection);
+            if (matchClearable && inSection) {
                 return true;
             }
         }
@@ -1435,6 +1458,10 @@
         return mDynamicPrivacyController.isInLockedDownShade();
     }
 
+    public boolean isLongPressInProgress() {
+        return mLongPressedView != null;
+    }
+
     /**
      * Set the dimmed state for all of the notification views.
      */
@@ -1689,17 +1716,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()
@@ -1727,7 +1760,7 @@
                 InteractionJankMonitor.getInstance().begin(mView,
                         CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
             }
-            return swipeWantsIt || scrollWantsIt || expandWantsIt;
+            return swipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt;
         }
 
         @Override
@@ -1736,11 +1769,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);
@@ -1754,12 +1791,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
@@ -1785,7 +1822,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 2c810c9..8be5de7 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
@@ -366,6 +366,20 @@
         return stackHeight / stackEndHeight;
     }
 
+    public boolean hasOngoingNotifs(StackScrollAlgorithmState algorithmState) {
+        for (int i = 0; i < algorithmState.visibleChildren.size(); i++) {
+            View child = algorithmState.visibleChildren.get(i);
+            if (!(child instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            if (!row.canViewBeDismissed()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     // TODO(b/172289889) polish shade open from HUN
     /**
      * Populates the {@link ExpandableViewState} for a single child.
@@ -430,7 +444,9 @@
                         + view.getIntrinsicHeight();
                 final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
                 ((FooterView.FooterViewState) viewState).hideContent =
-                        isShelfShowing || noSpaceForFooter;
+                        isShelfShowing || noSpaceForFooter
+                                || (ambientState.isDismissAllInProgress()
+                                && !hasOngoingNotifs(algorithmState));
             }
         } else {
             if (view != ambientState.getTrackedHeadsUpRow()) {
@@ -467,7 +483,6 @@
                     }
                 }
             }
-
             // Clip height of view right before shelf.
             viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction);
         }
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..e3a4bf0 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
@@ -46,7 +46,7 @@
     public static final int ANIMATION_DURATION_WAKEUP = 500;
     public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
     public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
-    public static final int ANIMATION_DURATION_SWIPE = 260;
+    public static final int ANIMATION_DURATION_SWIPE = 200;
     public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
     public static final int ANIMATION_DURATION_CLOSE_REMOTE_INPUT = 150;
     public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 400;
@@ -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 1bd26c3..45348d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -42,6 +42,8 @@
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.OperatorNameView;
+import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -90,8 +92,8 @@
     private int mDisabled2;
     private Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
     private DarkIconManager mDarkIconManager;
-    private View mOperatorNameFrame;
     private final CommandQueue mCommandQueue;
+    private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
     private final OngoingCallController mOngoingCallController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
     private final StatusBarLocationPublisher mLocationPublisher;
@@ -114,6 +116,7 @@
             disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
         }
     };
+    private OperatorNameViewController mOperatorNameViewController;
 
     @Inject
     public CollapsedStatusBarFragment(
@@ -127,7 +130,8 @@
             NetworkController networkController,
             StatusBarStateController statusBarStateController,
             Lazy<Optional<StatusBar>> statusBarOptionalLazy,
-            CommandQueue commandQueue
+            CommandQueue commandQueue,
+            OperatorNameViewController.Factory operatorNameViewControllerFactory
     ) {
         mOngoingCallController = ongoingCallController;
         mAnimationScheduler = animationScheduler;
@@ -140,6 +144,7 @@
         mStatusBarStateController = statusBarStateController;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
         mCommandQueue = commandQueue;
+        mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
     }
 
     @Override
@@ -411,14 +416,14 @@
     }
 
     public void hideOperatorName(boolean animate) {
-        if (mOperatorNameFrame != null) {
-            animateHide(mOperatorNameFrame, animate);
+        if (mOperatorNameViewController != null) {
+            animateHide(mOperatorNameViewController.getView(), animate);
         }
     }
 
     public void showOperatorName(boolean animate) {
-        if (mOperatorNameFrame != null) {
-            animateShow(mOperatorNameFrame, animate);
+        if (mOperatorNameViewController != null) {
+            animateShow(mOperatorNameViewController.getView(), animate);
         }
     }
 
@@ -495,7 +500,9 @@
     private void initOperatorName() {
         if (getResources().getBoolean(R.bool.config_showOperatorNameInStatusBar)) {
             ViewStub stub = mStatusBar.findViewById(R.id.operator_name);
-            mOperatorNameFrame = stub.inflate();
+            mOperatorNameViewController =
+                    mOperatorNameViewControllerFactory.create((OperatorNameView) stub.inflate());
+            mOperatorNameViewController.init();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 07618da..12ae3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -17,6 +17,7 @@
 import android.content.Context
 import android.content.pm.ActivityInfo
 import android.content.res.Configuration
+import android.graphics.Rect
 import android.os.LocaleList
 import android.view.View.LAYOUT_DIRECTION_RTL
 import com.android.systemui.statusbar.policy.ConfigurationController
@@ -29,6 +30,7 @@
     private val lastConfig = Configuration()
     private var density: Int = 0
     private var smallestScreenWidth: Int = 0
+    private var maxBounds: Rect? = null
     private var fontScale: Float = 0.toFloat()
     private val inCarMode: Boolean
     private var uiMode: Int = 0
@@ -85,6 +87,14 @@
             }
         }
 
+        val maxBounds = newConfig.windowConfiguration.maxBounds
+        if (maxBounds != this.maxBounds) {
+            this.maxBounds = maxBounds
+            listeners.filterForEach({ this.listeners.contains(it) }) {
+                it.onMaxBoundsChanged()
+            }
+        }
+
         val localeList = newConfig.locales
         if (localeList != this.localeList) {
             this.localeList = localeList
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 7908d84..84b8f52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -268,6 +268,13 @@
     }
 
     /**
+     * Whether the brightness sensor uses the proximity sensor.
+     */
+    public boolean brightnessUsesProx() {
+        return mResources.getBoolean(R.bool.doze_brightness_uses_prox);
+    }
+
+    /**
      * Callback to listen for DozeParameter changes.
      */
     public void addCallback(Callback callback) {
@@ -303,6 +310,7 @@
         pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
         pw.print("getSelectivelyRegisterSensorsUsingProx(): ");
         pw.println(getSelectivelyRegisterSensorsUsingProx());
+        pw.print("brightnessUsesProx(): "); pw.println(brightnessUsesProx());
     }
 
     interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index b2cf72a..21c3e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -116,11 +116,18 @@
 
         if (!mDozing || mPulseCallback != null) {
             if (DEBUG) {
-                Log.d(TAG, "Pulse supressed. Dozing: " + mDozeParameters + " had callback? "
+                Log.d(TAG, "Pulse suppressed. Dozing: " + mDozeParameters + " had callback? "
                         + (mPulseCallback != null));
             }
             // Pulse suppressed.
             callback.onPulseFinished();
+            if (!mDozing) {
+                mDozeLog.tracePulseDropped("device isn't dozing");
+            } else {
+                mDozeLog.tracePulseDropped("already has pulse callback mPulseCallback="
+                        + mPulseCallback);
+            }
+
             return;
         }
 
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 0a4e59c..c639eec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -80,6 +80,7 @@
 import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.camera.CameraIntents;
@@ -203,13 +204,15 @@
     private ControlsListingController.ControlsListingCallback mListingCallback =
             new ControlsListingController.ControlsListingCallback() {
                 public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) {
-                    boolean available = !serviceInfos.isEmpty();
+                    post(() -> {
+                        boolean available = !serviceInfos.isEmpty();
 
-                    if (available != mControlServicesAvailable) {
-                        mControlServicesAvailable = available;
-                        updateControlsVisibility();
-                        updateAffordanceColors();
-                    }
+                        if (available != mControlServicesAvailable) {
+                            mControlServicesAvailable = available;
+                            updateControlsVisibility();
+                            updateAffordanceColors();
+                        }
+                    });
                 }
             };
 
@@ -1044,11 +1047,13 @@
             return;
         }
 
+        ActivityLaunchAnimator.Controller animationController = createLaunchAnimationController(v);
         if (mHasCard) {
             Intent intent = new Intent(mContext, WalletActivity.class)
                     .setAction(Intent.ACTION_VIEW)
                     .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivity(intent);
+            mActivityStarter.startActivity(intent, true /* dismissShade */, animationController,
+                    true /* showOverLockscreenWhenLocked */);
         } else {
             if (mQuickAccessWalletController.getWalletClient().createWalletIntent() == null) {
                 Log.w(TAG, "Could not get intent of the wallet app.");
@@ -1056,10 +1061,14 @@
             }
             mActivityStarter.postStartActivityDismissingKeyguard(
                     mQuickAccessWalletController.getWalletClient().createWalletIntent(),
-                    /* delay= */ 0);
+                    /* delay= */ 0, animationController);
         }
     }
 
+    protected ActivityLaunchAnimator.Controller createLaunchAnimationController(View view) {
+        return ActivityLaunchAnimator.Controller.fromView(view, null);
+    }
+
     private void onControlsClick(View v) {
         if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
             return;
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 19c2585..d348954 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -32,6 +32,7 @@
  * Utility class to calculate the clock position and top padding of notifications on Keyguard.
  */
 public class KeyguardClockPositionAlgorithm {
+
     /**
      * Margin between the bottom of the status view and the notification shade.
      */
@@ -67,12 +68,6 @@
     private int mCutoutTopInset = 0;
 
     /**
-     * Maximum bottom padding to avoid overlap with {@link KeyguardBottomAreaView} or
-     * the ambient indication.
-     */
-    private int mMaxShadeBottom;
-
-    /**
      * Recommended distance from the status bar.
      */
     private int mContainerTopPadding;
@@ -88,14 +83,9 @@
     private int mBurnInPreventionOffsetX;
 
     /**
-     * Burn-in prevention y translation.
+     * Burn-in prevention y translation for clock layouts.
      */
-    private int mBurnInPreventionOffsetY;
-
-    /**
-     * Burn-in prevention y translation for large clock layouts.
-     */
-    private int mBurnInPreventionOffsetYLargeClock;
+    private int mBurnInPreventionOffsetYClock;
 
     /**
      * Doze/AOD transition amount.
@@ -121,7 +111,6 @@
     private int mUnlockedStackScrollerPadding;
 
     private boolean mIsSplitShade;
-    private int mSplitShadeSmartspaceHeight;
 
     /**
      * Refreshes the dimension values.
@@ -134,35 +123,30 @@
                 res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) / 2;
         mBurnInPreventionOffsetX = res.getDimensionPixelSize(
                 R.dimen.burn_in_prevention_offset_x);
-        mBurnInPreventionOffsetY = res.getDimensionPixelSize(
-                R.dimen.burn_in_prevention_offset_y);
-        mBurnInPreventionOffsetYLargeClock = res.getDimensionPixelSize(
-                R.dimen.burn_in_prevention_offset_y_large_clock);
+        mBurnInPreventionOffsetYClock = res.getDimensionPixelSize(
+                R.dimen.burn_in_prevention_offset_y_clock);
     }
 
     /**
      * Sets up algorithm values.
      */
-    public void setup(int keyguardStatusBarHeaderHeight, int maxShadeBottom,
-            float panelExpansion,
-            int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY, float dark,
-            float overStrechAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
-            float qsExpansion, int cutoutTopInset, int splitShadeSmartspaceHeight,
+    public void setup(int keyguardStatusBarHeaderHeight, float panelExpansion,
+            int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
+            float dark, float overStretchAmount, boolean bypassEnabled,
+            int unlockedStackScrollerPadding, float qsExpansion, int cutoutTopInset,
             boolean isSplitShade) {
         mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
                 userSwitchHeight);
-        mMaxShadeBottom = maxShadeBottom;
         mPanelExpansion = panelExpansion;
         mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
         mUserSwitchHeight = userSwitchHeight;
         mUserSwitchPreferredY = userSwitchPreferredY;
         mDarkAmount = dark;
-        mOverStretchAmount = overStrechAmount;
+        mOverStretchAmount = overStretchAmount;
         mBypassEnabled = bypassEnabled;
         mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
         mQsExpansion = qsExpansion;
         mCutoutTopInset = cutoutTopInset;
-        mSplitShadeSmartspaceHeight = splitShadeSmartspaceHeight;
         mIsSplitShade = isSplitShade;
     }
 
@@ -184,7 +168,7 @@
         if (mBypassEnabled) {
             return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
         } else if (mIsSplitShade) {
-            return clockYPosition + mSplitShadeSmartspaceHeight;
+            return clockYPosition;
         } else {
             return clockYPosition + mKeyguardStatusHeight;
         }
@@ -215,8 +199,8 @@
 
         // This will keep the clock at the top but out of the cutout area
         float shift = 0;
-        if (clockY - mBurnInPreventionOffsetYLargeClock < mCutoutTopInset) {
-            shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYLargeClock);
+        if (clockY - mBurnInPreventionOffsetYClock < mCutoutTopInset) {
+            shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYClock);
         }
         float clockYDark = clockY + burnInPreventionOffsetY() + shift;
 
@@ -252,7 +236,7 @@
     }
 
     private float burnInPreventionOffsetY() {
-        int offset = mBurnInPreventionOffsetYLargeClock;
+        int offset = mBurnInPreventionOffsetYClock;
 
         return getBurnInOffset(offset * 2, false /* xAxis */) - offset;
     }
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 a73cad7..df4bbcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -321,7 +321,7 @@
         }
     }
 
-    public void setKeyguardUserSwitcherEnabled(boolean enabled) {
+    void setKeyguardUserSwitcherEnabled(boolean enabled) {
         mKeyguardUserSwitcherEnabled = enabled;
     }
 
@@ -475,8 +475,10 @@
 
     /**
      * Set the clipping on the top of the view.
+     *
+     * Should only be called from {@link KeyguardStatusBarViewController}.
      */
-    public void setTopClipping(int topClipping) {
+    void setTopClipping(int topClipping) {
         if (topClipping != mTopClipping) {
             mTopClipping = topClipping;
             updateClipping();
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 bfadc3f..893aa6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -16,21 +16,38 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.res.Resources;
+import android.hardware.biometrics.BiometricSourceType;
+import android.util.MathUtils;
+import android.view.View;
 
 import androidx.annotation.NonNull;
 
 import com.android.keyguard.CarrierTextController;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+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.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.util.ViewController;
 
@@ -44,6 +61,21 @@
 
 /** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
 public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
+    private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
+            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+    private float mKeyguardHeadsUpShowingAmount = 0.0f;
+    private final AnimatableProperty mHeadsUpShowingAmountAnimation = AnimatableProperty.from(
+            "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
+            (view, aFloat) -> {
+                mKeyguardHeadsUpShowingAmount = aFloat;
+                updateViewState();
+            },
+            view -> mKeyguardHeadsUpShowingAmount,
+            R.id.keyguard_hun_animator_tag,
+            R.id.keyguard_hun_animator_end_tag,
+            R.id.keyguard_hun_animator_start_tag);
+
     private final CarrierTextController mCarrierTextController;
     private final ConfigurationController mConfigurationController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
@@ -52,6 +84,13 @@
     private final StatusBarIconController mStatusBarIconController;
     private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
     private final BatteryMeterViewController mBatteryMeterViewController;
+    private final NotificationPanelViewController.NotificationPanelViewStateProvider
+            mNotificationPanelViewStateProvider;
+    private final KeyguardStateController mKeyguardStateController;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final BiometricUnlockController mBiometricUnlockController;
+    private final SysuiStatusBarStateController mStatusBarStateController;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -103,11 +142,80 @@
     private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
             (name, picture, userAccount) -> mView.onUserInfoChanged(picture);
 
+    private final ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener =
+            animation -> {
+                mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
+                updateViewState();
+            };
+
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onBiometricAuthenticated(
+                        int userId,
+                        BiometricSourceType biometricSourceType,
+                        boolean isStrongBiometric) {
+                    if (mFirstBypassAttempt
+                            && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                                    isStrongBiometric)) {
+                        mDelayShowingKeyguardStatusBar = true;
+                    }
+                }
+
+                @Override
+                public void onBiometricRunningStateChanged(
+                        boolean running,
+                        BiometricSourceType biometricSourceType) {
+                    boolean keyguardOrShadeLocked =
+                            mStatusBarState == KEYGUARD
+                                    || mStatusBarState == StatusBarState.SHADE_LOCKED;
+                    if (!running
+                            && mFirstBypassAttempt
+                            && keyguardOrShadeLocked
+                            && !mDozing
+                            && !mDelayShowingKeyguardStatusBar
+                            && !mBiometricUnlockController.isBiometricUnlock()) {
+                        mFirstBypassAttempt = false;
+                        animateKeyguardStatusBarIn();
+                    }
+                }
+
+                @Override
+                public void onFinishedGoingToSleep(int why) {
+                    mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
+                    mDelayShowingKeyguardStatusBar = false;
+                }
+            };
+
+    private final StatusBarStateController.StateListener mStatusBarStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStateChanged(int newState) {
+                    mStatusBarState = newState;
+                }
+            };
+
     private final List<String> mBlockedIcons;
+    private final int mNotificationsHeaderCollideDistance;
 
     private boolean mBatteryListening;
     private StatusBarIconController.TintedIconManager mTintedIconManager;
 
+    private float mKeyguardStatusBarAnimateAlpha = 1f;
+    /**
+     * If face auth with bypass is running for the first time after you turn on the screen.
+     * (From aod or screen off)
+     */
+    private boolean mFirstBypassAttempt;
+    /**
+     * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
+     * the keyguard is dismissed to show the status bar.
+     */
+    private boolean mDelayShowingKeyguardStatusBar;
+    private int mStatusBarState;
+    private boolean mDozing;
+    private boolean mShowingKeyguardHeadsUp;
+
     @Inject
     public KeyguardStatusBarViewController(
             KeyguardStatusBarView view,
@@ -118,7 +226,14 @@
             UserInfoController userInfoController,
             StatusBarIconController statusBarIconController,
             StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
-            BatteryMeterViewController batteryMeterViewController) {
+            BatteryMeterViewController batteryMeterViewController,
+            NotificationPanelViewController.NotificationPanelViewStateProvider
+                    notificationPanelViewStateProvider,
+            KeyguardStateController keyguardStateController,
+            KeyguardBypassController bypassController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            BiometricUnlockController biometricUnlockController,
+            SysuiStatusBarStateController statusBarStateController) {
         super(view);
         mCarrierTextController = carrierTextController;
         mConfigurationController = configurationController;
@@ -128,12 +243,33 @@
         mStatusBarIconController = statusBarIconController;
         mTintedIconManagerFactory = tintedIconManagerFactory;
         mBatteryMeterViewController = batteryMeterViewController;
+        mNotificationPanelViewStateProvider = notificationPanelViewStateProvider;
+        mKeyguardStateController = keyguardStateController;
+        mKeyguardBypassController = bypassController;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mBiometricUnlockController = biometricUnlockController;
+        mStatusBarStateController = statusBarStateController;
+
+        mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
+        mKeyguardStateController.addCallback(
+                new KeyguardStateController.Callback() {
+                    @Override
+                    public void onKeyguardFadingAwayChanged() {
+                        if (!mKeyguardStateController.isKeyguardFadingAway()) {
+                            mFirstBypassAttempt = false;
+                            mDelayShowingKeyguardStatusBar = false;
+                        }
+                    }
+                }
+        );
 
         Resources r = getResources();
         mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
                 r.getString(com.android.internal.R.string.status_bar_volume),
                 r.getString(com.android.internal.R.string.status_bar_alarm_clock),
                 r.getString(com.android.internal.R.string.status_bar_call_strength)));
+        mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
+                R.dimen.header_notifications_collide_distance);
     }
 
     @Override
@@ -148,6 +284,8 @@
         mConfigurationController.addCallback(mConfigurationListener);
         mAnimationScheduler.addCallback(mAnimationCallback);
         mUserInfoController.addCallback(mOnUserInfoChangedListener);
+        mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
         if (mTintedIconManager == null) {
             mTintedIconManager =
                     mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
@@ -159,14 +297,11 @@
 
     @Override
     protected void onViewDetached() {
-        // 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();
-
         mConfigurationController.removeCallback(mConfigurationListener);
         mAnimationScheduler.removeCallback(mAnimationCallback);
         mUserInfoController.removeCallback(mOnUserInfoChangedListener);
+        mStatusBarStateController.removeCallback(mStatusBarStateListener);
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
         if (mTintedIconManager != null) {
             mStatusBarIconController.removeIconGroup(mTintedIconManager);
         }
@@ -177,6 +312,11 @@
         mView.onThemeChanged(mTintedIconManager);
     }
 
+    /** Sets whether user switcher is enabled. */
+    public void setKeyguardUserSwitcherEnabled(boolean enabled) {
+        mView.setKeyguardUserSwitcherEnabled(enabled);
+    }
+
     /** Sets whether this controller should listen to battery updates. */
     public void setBatteryListening(boolean listening) {
         if (listening == mBatteryListening) {
@@ -190,10 +330,145 @@
         }
     }
 
+    /** Set the view to have no top clipping. */
+    public void setNoTopClipping() {
+        mView.setTopClipping(0);
+    }
+
+    /**
+     * Update the view's top clipping based on the value of notificationPanelTop and the view's
+     * current top.
+     *
+     * @param notificationPanelTop the current top of the notification panel view.
+     */
+    public void updateTopClipping(int notificationPanelTop) {
+        mView.setTopClipping(notificationPanelTop - mView.getTop());
+    }
+
+    /** Sets the dozing state. */
+    public void setDozing(boolean dozing) {
+        mDozing = dozing;
+    }
+
+    /** Animate the keyguard status bar in. */
+    public void animateKeyguardStatusBarIn() {
+        mView.setVisibility(View.VISIBLE);
+        mView.setAlpha(0f);
+        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+        anim.addUpdateListener(mAnimatorUpdateListener);
+        anim.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        anim.start();
+    }
+
+    /** Animate the keyguard status bar out. */
+    public void animateKeyguardStatusBarOut(long startDelay, long duration) {
+        ValueAnimator anim = ValueAnimator.ofFloat(mView.getAlpha(), 0f);
+        anim.addUpdateListener(mAnimatorUpdateListener);
+        anim.setStartDelay(startDelay);
+        anim.setDuration(duration);
+        anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mView.setVisibility(View.INVISIBLE);
+                mView.setAlpha(1f);
+                mKeyguardStatusBarAnimateAlpha = 1f;
+            }
+        });
+        anim.start();
+    }
+
+    /**
+     * Updates the {@link KeyguardStatusBarView} state based on what the
+     * {@link NotificationPanelViewController.NotificationPanelViewStateProvider} and other
+     * controllers provide.
+     */
+    public void updateViewState() {
+        if (!isKeyguardShowing()) {
+            return;
+        }
+
+        float alphaQsExpansion = 1 - Math.min(
+                1, mNotificationPanelViewStateProvider.getQsExpansionFraction() * 2);
+        float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
+                * mKeyguardStatusBarAnimateAlpha
+                * (1.0f - mKeyguardHeadsUpShowingAmount);
+
+        boolean hideForBypass =
+                mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
+                        || mDelayShowingKeyguardStatusBar;
+        int newVisibility = newAlpha != 0f && !mDozing && !hideForBypass
+                ? View.VISIBLE : View.INVISIBLE;
+
+        updateViewState(newAlpha, newVisibility);
+    }
+
+    /**
+     * Updates the {@link KeyguardStatusBarView} state based on the provided values.
+     */
+    public void updateViewState(float alpha, int visibility) {
+        mView.setAlpha(alpha);
+        mView.setVisibility(visibility);
+    }
+
+    /**
+     * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
+     * during swiping up.
+     */
+    private float getKeyguardContentsAlpha() {
+        float alpha;
+        if (isKeyguardShowing()) {
+            // When on Keyguard, we hide the header as soon as we expanded close enough to the
+            // header
+            alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+                    / (mView.getHeight() + mNotificationsHeaderCollideDistance);
+        } else {
+            // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
+            // soon as we start translating the stack.
+            alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+                    / mView.getHeight();
+        }
+        alpha = MathUtils.saturate(alpha);
+        alpha = (float) Math.pow(alpha, 0.75);
+        return alpha;
+    }
+
+    /**
+     * Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
+     * whether heads up is visible.
+     */
+    public void updateForHeadsUp() {
+        updateForHeadsUp(true);
+    }
+
+    void updateForHeadsUp(boolean animate) {
+        boolean showingKeyguardHeadsUp =
+                isKeyguardShowing() && mNotificationPanelViewStateProvider.shouldHeadsUpBeVisible();
+        if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
+            mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
+            if (isKeyguardShowing()) {
+                PropertyAnimator.setProperty(
+                        mView,
+                        mHeadsUpShowingAmountAnimation,
+                        showingKeyguardHeadsUp ? 1.0f : 0.0f,
+                        KEYGUARD_HUN_PROPERTIES,
+                        animate);
+            } else {
+                PropertyAnimator.applyImmediately(mView, mHeadsUpShowingAmountAnimation, 0.0f);
+            }
+        }
+    }
+
+    private boolean isKeyguardShowing() {
+        return mStatusBarState == KEYGUARD;
+    }
+
     /** */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("KeyguardStatusBarView:");
         pw.println("  mBatteryListening: " + mBatteryListening);
         mView.dump(fd, pw, args);
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
index 094ebb9..5f222af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -24,7 +24,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.dagger.SysUISingleton;
@@ -88,10 +87,11 @@
     }
 
     private ArrayMap<Integer, Integer> mLegacyMap;
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+    private final MetricsLogger mMetricsLogger;
 
     @Inject
-    public LockscreenGestureLogger() {
+    public LockscreenGestureLogger(MetricsLogger metricsLogger) {
+        mMetricsLogger = metricsLogger;
         mLegacyMap = new ArrayMap<>(EventLogConstants.METRICS_GESTURE_TYPE_MAP.length);
         for (int i = 0; i < EventLogConstants.METRICS_GESTURE_TYPE_MAP.length ; i++) {
             mLegacyMap.put(EventLogConstants.METRICS_GESTURE_TYPE_MAP[i], i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
index f27c7d2..2cacf92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
@@ -23,10 +23,12 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSDetailDisplayer;
 import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.qs.user.UserSwitchDialogController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.util.ViewController;
 
@@ -39,6 +41,8 @@
     private final UserSwitcherController mUserSwitcherController;
     private final QSDetailDisplayer mQsDetailDisplayer;
     private final FalsingManager mFalsingManager;
+    private final UserSwitchDialogController mUserSwitchDialogController;
+    private final FeatureFlags mFeatureFlags;
 
     private UserSwitcherController.BaseUserAdapter mUserListener;
 
@@ -49,26 +53,33 @@
                 return;
             }
 
-            View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
+            if (mFeatureFlags.useNewUserSwitcher()) {
+                mUserSwitchDialogController.showDialog(v);
+            } else {
+                View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
 
-            int[] tmpInt = new int[2];
-            center.getLocationInWindow(tmpInt);
-            tmpInt[0] += center.getWidth() / 2;
-            tmpInt[1] += center.getHeight() / 2;
+                int[] tmpInt = new int[2];
+                center.getLocationInWindow(tmpInt);
+                tmpInt[0] += center.getWidth() / 2;
+                tmpInt[1] += center.getHeight() / 2;
 
-            mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
+                mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
+            }
         }
     };
 
     @Inject
     public MultiUserSwitchController(MultiUserSwitch view, UserManager userManager,
             UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer,
-            FalsingManager falsingManager) {
+            FalsingManager falsingManager, UserSwitchDialogController userSwitchDialogController,
+            FeatureFlags featureFlags) {
         super(view);
         mUserManager = userManager;
         mUserSwitcherController = userSwitcherController;
         mQsDetailDisplayer = qsDetailDisplayer;
         mFalsingManager = falsingManager;
+        mUserSwitchDialogController = userSwitchDialogController;
+        mFeatureFlags = featureFlags;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 7a131b2..2c95ae4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -28,6 +28,8 @@
 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
@@ -55,7 +57,6 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricSourceType;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -92,13 +93,13 @@
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.LockIconViewController;
 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.Interpolators;
@@ -107,13 +108,16 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.communal.CommunalHostView;
 import com.android.systemui.communal.CommunalHostViewController;
+import com.android.systemui.communal.CommunalHostViewPositionAlgorithm;
 import com.android.systemui.communal.CommunalSource;
 import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.communal.CommunalStateController;
 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.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.idle.IdleHostView;
@@ -122,6 +126,7 @@
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
@@ -147,7 +152,6 @@
 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;
@@ -189,7 +193,6 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
-import java.util.function.Function;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -240,11 +243,9 @@
     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();
-    private final BiometricUnlockController mBiometricUnlockController;
     private final NotificationPanelView mView;
     private final VibratorHelper mVibratorHelper;
     private final MetricsLogger mMetricsLogger;
@@ -272,54 +273,8 @@
     private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1);
     private static final Rect EMPTY_RECT = new Rect();
 
-    private final AnimatableProperty KEYGUARD_HEADS_UP_SHOWING_AMOUNT = AnimatableProperty.from(
-            "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
-            (notificationPanelView, aFloat) -> setKeyguardHeadsUpShowingAmount(aFloat),
-            (Function<NotificationPanelView, Float>) notificationPanelView ->
-                    getKeyguardHeadsUpShowingAmount(),
-            R.id.keyguard_hun_animator_tag, R.id.keyguard_hun_animator_end_tag,
-            R.id.keyguard_hun_animator_start_tag);
-    private static final AnimationProperties
-            KEYGUARD_HUN_PROPERTIES =
-            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-    @VisibleForTesting
-    final KeyguardUpdateMonitorCallback
-            mKeyguardUpdateCallback =
-            new KeyguardUpdateMonitorCallback() {
-
-                @Override
-                public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType,
-                        boolean isStrongBiometric) {
-                    if (mFirstBypassAttempt
-                            && mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
-                        mDelayShowingKeyguardStatusBar = true;
-                    }
-                }
-
-                @Override
-                public void onBiometricRunningStateChanged(boolean running,
-                        BiometricSourceType biometricSourceType) {
-                    boolean
-                            keyguardOrShadeLocked =
-                            mBarState == KEYGUARD
-                                    || mBarState == StatusBarState.SHADE_LOCKED;
-                    if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
-                            && !mDelayShowingKeyguardStatusBar
-                            && !mBiometricUnlockController.isBiometricUnlock()) {
-                        mFirstBypassAttempt = false;
-                        animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-                    }
-                }
-
-                @Override
-                public void onFinishedGoingToSleep(int why) {
-                    mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
-                    mDelayShowingKeyguardStatusBar = false;
-                }
-    };
-
     private final LayoutInflater mLayoutInflater;
+    private final FeatureFlags mFeatureFlags;
     private final PowerManager mPowerManager;
     private final AccessibilityManager mAccessibilityManager;
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
@@ -327,6 +282,7 @@
     private final KeyguardBypassController mKeyguardBypassController;
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final CommunalSourceMonitor mCommunalSourceMonitor;
+    private final CommunalStateController mCommunalStateController;
     private final ConversationNotificationManager mConversationNotificationManager;
     private final AuthController mAuthController;
     private final MediaHierarchyManager mMediaHierarchyManager;
@@ -374,8 +330,6 @@
     private IdleHostViewController mIdleHostViewController;
     private LockIconViewController mLockIconViewController;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
-    private FrameLayout mSplitShadeSmartspaceContainer;
-
     private boolean mAnimateNextPositionUpdate;
     private float mQuickQsOffsetHeight;
     private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -418,7 +372,6 @@
     private FlingAnimationUtils mFlingAnimationUtils;
     private int mStatusBarMinHeight;
     private int mStatusBarHeaderHeightKeyguard;
-    private int mNotificationsHeaderCollideDistance;
     private float mOverStretchAmount;
     private float mDownX;
     private float mDownY;
@@ -432,6 +385,12 @@
     private final KeyguardClockPositionAlgorithm.Result
             mClockPositionResult =
             new KeyguardClockPositionAlgorithm.Result();
+    private final CommunalHostViewPositionAlgorithm
+            mCommunalPositionAlgorithm =
+            new CommunalHostViewPositionAlgorithm();
+    private final CommunalHostViewPositionAlgorithm.Result
+            mCommunalPositionResult =
+            new CommunalHostViewPositionAlgorithm.Result();
     private boolean mIsExpanding;
 
     private boolean mBlockTouches;
@@ -455,7 +414,6 @@
     private boolean mQsTouchAboveFalsingThreshold;
     private int mQsFalsingThreshold;
 
-    private float mKeyguardStatusBarAnimateAlpha = 1f;
     private HeadsUpTouchHelper mHeadsUpTouchHelper;
     private boolean mListenForHeadsUp;
     private int mNavigationBarBottomHeight;
@@ -501,7 +459,6 @@
     private float mLinearDarkAmount;
 
     private boolean mPulsing;
-    private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mUserSetupComplete;
     private int mQsNotificationTopPadding;
     private boolean mHideIconsDuringLaunchAnimation = true;
@@ -555,6 +512,8 @@
     private final NotificationLockscreenUserManager mLockscreenUserManager;
     private final UserManager mUserManager;
     private final MediaDataManager mMediaDataManager;
+    private final SysUiState mSysUiState;
+
     private NotificationShadeDepthController mDepthController;
     private int mDisplayId;
 
@@ -570,8 +529,6 @@
     private int mDarkIconSize;
     private int mHeadsUpInset;
     private boolean mHeadsUpPinnedMode;
-    private float mKeyguardHeadsUpShowingAmount = 0.0f;
-    private boolean mShowingKeyguardHeadsUp;
     private boolean mAllowExpandForSmallExpansion;
     private Runnable mExpandAfterLayoutRunnable;
 
@@ -630,17 +587,6 @@
      */
     private boolean mIsPanelCollapseOnQQS;
 
-    /**
-     * If face auth with bypass is running for the first time after you turn on the screen.
-     * (From aod or screen off)
-     */
-    private boolean mFirstBypassAttempt;
-    /**
-     * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
-     * the keyguard is dismissed to show the status bar.
-     */
-    private boolean mDelayShowingKeyguardStatusBar;
-
     private boolean mAnimatingQS;
 
     /**
@@ -690,7 +636,7 @@
 
     private KeyguardMediaController mKeyguardMediaController;
 
-    private boolean mStatusViewCentered = false;
+    private boolean mStatusViewCentered = true;
 
     private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
         @Override
@@ -712,6 +658,32 @@
         }
     };
 
+    private final CommunalStateController.Callback mCommunalStateCallback =
+            new CommunalStateController.Callback() {
+                @Override
+                public void onCommunalViewShowingChanged() {
+                    mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
+                            mBarState,
+                            mKeyguardStateController.isKeyguardFadingAway(),
+                            mStatusBarStateController.goingToFullShade(),
+                            mBarState);
+                    if (mKeyguardUserSwitcherController != null) {
+                        mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility(
+                                mBarState,
+                                mKeyguardStateController.isKeyguardFadingAway(),
+                                mStatusBarStateController.goingToFullShade(),
+                                mBarState);
+                    }
+                    if (mKeyguardQsUserSwitchController != null) {
+                        mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility(
+                                mBarState,
+                                mKeyguardStateController.isKeyguardFadingAway(),
+                                mStatusBarStateController.goingToFullShade(),
+                                mBarState);
+                    }
+                }
+    };
+
     private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
         @Override
         public void onDoubleTapRequired() {
@@ -730,12 +702,14 @@
             @Main Resources resources,
             @Main Handler handler,
             LayoutInflater layoutInflater,
+            FeatureFlags featureFlags,
             NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardBypassController bypassController, FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             NotificationEntryManager notificationEntryManager,
+            CommunalStateController communalStateController,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController, DozeLog dozeLog,
             DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper,
@@ -749,7 +723,6 @@
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             ConversationNotificationManager conversationNotificationManager,
             MediaHierarchyManager mediaHierarchyManager,
-            BiometricUnlockController biometricUnlockController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
             KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
@@ -780,14 +753,22 @@
             @Main Executor uiExecutor,
             SecureSettings secureSettings,
             SplitShadeHeaderController splitShadeHeaderController,
-            LockscreenSmartspaceController lockscreenSmartspaceController,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+            LockscreenGestureLogger lockscreenGestureLogger,
             NotificationRemoteInputManager remoteInputManager,
             ControlsComponent controlsComponent) {
-        super(view, falsingManager, dozeLog, keyguardStateController,
-                (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
-                statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
-                statusBarTouchableRegionManager, ambientState);
+        super(view,
+                falsingManager,
+                dozeLog,
+                keyguardStateController,
+                (SysuiStatusBarStateController) statusBarStateController,
+                vibratorHelper,
+                statusBarKeyguardViewManager,
+                latencyTracker,
+                flingAnimationUtilsBuilder.get(),
+                statusBarTouchableRegionManager,
+                lockscreenGestureLogger,
+                ambientState);
         mView = view;
         mVibratorHelper = vibratorHelper;
         mKeyguardMediaController = keyguardMediaController;
@@ -803,6 +784,7 @@
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
         mGroupManager = groupManager;
         mNotificationIconAreaController = notificationIconAreaController;
+        mCommunalStateController = communalStateController;
         mCommunalViewComponentFactory = communalViewComponentFactory;
         mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
         mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
@@ -814,12 +796,12 @@
         mQSDetailDisplayer = qsDetailDisplayer;
         mFragmentService = fragmentService;
         mSettingsChangeObserver = new SettingsChangeObserver(handler);
-        mLockscreenSmartspaceController = lockscreenSmartspaceController;
         mShouldUseSplitNotificationShade =
                 Utils.shouldUseSplitNotificationShade(mResources);
         mView.setWillNotDraw(!DEBUG);
         mSplitShadeHeaderController = splitShadeHeaderController;
         mLayoutInflater = layoutInflater;
+        mFeatureFlags = featureFlags;
         mFalsingManager = falsingManager;
         mFalsingCollector = falsingCollector;
         mPowerManager = powerManager;
@@ -832,7 +814,6 @@
         mDisplayId = displayId;
         mPulseExpansionHandler = pulseExpansionHandler;
         mDozeParameters = dozeParameters;
-        mBiometricUnlockController = biometricUnlockController;
         mScrimController = scrimController;
         mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
         mUserManager = userManager;
@@ -840,6 +821,8 @@
         mTapAgainViewController = tapAgainViewController;
         mUiExecutor = uiExecutor;
         mSecureSettings = secureSettings;
+        // TODO: inject via dagger instead of Dependency
+        mSysUiState = Dependency.get(SysUiState.class);
         pulseExpansionHandler.setPulseExpandAbortListener(() -> {
             if (mQs != null) {
                 mQs.animateHeaderSlidingOut();
@@ -849,21 +832,8 @@
         mKeyguardBypassController = bypassController;
         mUpdateMonitor = keyguardUpdateMonitor;
         mCommunalSourceMonitor = communalSourceMonitor;
-        mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
-        KeyguardStateController.Callback
-                keyguardMonitorCallback =
-                new KeyguardStateController.Callback() {
-                    @Override
-                    public void onKeyguardFadingAwayChanged() {
-                        if (!mKeyguardStateController.isKeyguardFadingAway()) {
-                            mFirstBypassAttempt = false;
-                            mDelayShowingKeyguardStatusBar = false;
-                        }
-                    }
-                };
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         lockscreenShadeTransitionController.setNotificationPanelController(this);
-        mKeyguardStateController.addCallback(keyguardMonitorCallback);
         DynamicPrivacyControlListener
                 dynamicPrivacyControlListener =
                 new DynamicPrivacyControlListener();
@@ -911,9 +881,6 @@
         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;
@@ -928,13 +895,33 @@
             }
         }
 
+        mKeyguardStatusBarViewController =
+                mKeyguardStatusBarViewComponentFactory.build(
+                        mKeyguardStatusBar,
+                        mNotificationPanelViewStateProvider)
+                        .getKeyguardStatusBarViewController();
+        mKeyguardStatusBarViewController.init();
+
+        IdleViewComponent idleViewComponent = mIdleViewComponentFactory
+                .build(mView.findViewById(R.id.idle_host_view));
+        mIdleHostViewController = idleViewComponent.getIdleHostViewController();
+        mIdleHostViewController.init();
+
+        if (mCommunalView != null) {
+            CommunalViewComponent communalViewComponent =
+                    mCommunalViewComponentFactory.build(mCommunalView);
+            mCommunalViewController =
+                    communalViewComponent.getCommunalHostViewController();
+            mCommunalViewController.init();
+        }
+
+
         updateViewControllers(
                 mView.findViewById(R.id.keyguard_status_view),
                 userAvatarView,
-                mKeyguardStatusBar,
                 keyguardUserSwitcherView,
-                mCommunalView,
-                mView.findViewById(R.id.idle_host_view));
+                mView.findViewById(R.id.idle_host_view),
+                mCommunalView);
         mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
         NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
                 R.id.notification_stack_scroller);
@@ -961,7 +948,7 @@
         mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
             @Override
             public void onFullyHiddenChanged(boolean isFullyHidden) {
-                updateKeyguardStatusBarForHeadsUp();
+                mKeyguardStatusBarViewController.updateForHeadsUp();
             }
 
             @Override
@@ -998,8 +985,6 @@
         mStatusBarHeaderHeightKeyguard = mResources.getDimensionPixelSize(
                 R.dimen.status_bar_header_height_keyguard);
         mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height);
-        mNotificationsHeaderCollideDistance = mResources.getDimensionPixelSize(
-                R.dimen.header_notifications_collide_distance);
         mClockPositionAlgorithm.loadDimens(mResources);
         mQsFalsingThreshold = mResources.getDimensionPixelSize(R.dimen.qs_falsing_threshold);
         mPositionMinSideMargin = mResources.getDimensionPixelSize(
@@ -1018,17 +1003,17 @@
                 R.dimen.pulse_expansion_max_top_overshoot);
         mScrimCornerRadius = mResources.getDimensionPixelSize(
                 R.dimen.notification_scrim_corner_radius);
-        mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(mResources);
+        mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(
+                mView.getContext());
         mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
                 R.dimen.notification_side_paddings);
     }
 
     private void updateViewControllers(KeyguardStatusView keyguardStatusView,
             UserAvatarView userAvatarView,
-            KeyguardStatusBarView keyguardStatusBarView,
             KeyguardUserSwitcherView keyguardUserSwitcherView,
-            CommunalHostView communalView,
-            IdleHostView idleHostView) {
+            IdleHostView idleHostView,
+            CommunalHostView communalView) {
         // Re-associate the KeyguardStatusViewController
         KeyguardStatusViewComponent statusViewComponent =
                 mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
@@ -1039,24 +1024,6 @@
         mIdleHostViewController = idleViewComponent.getIdleHostViewController();
         mIdleHostViewController.init();
 
-        KeyguardStatusBarViewComponent statusBarViewComponent =
-                mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
-        if (mKeyguardStatusBarViewController != null) {
-            // TODO(b/194181195): This shouldn't be necessary.
-            mKeyguardStatusBarViewController.onViewDetached();
-        }
-        mKeyguardStatusBarViewController =
-                statusBarViewComponent.getKeyguardStatusBarViewController();
-        mKeyguardStatusBarViewController.init();
-
-        if (communalView != null) {
-            CommunalViewComponent communalViewComponent =
-                    mCommunalViewComponentFactory.build(communalView);
-            mCommunalViewController =
-                    communalViewComponent.getCommunalHostViewController();
-            mCommunalViewController.init();
-        }
-
         if (mKeyguardUserSwitcherController != null) {
             // Try to close the switcher so that callbacks are triggered if necessary.
             // Otherwise, NPV can get into a state where some of the views are still hidden
@@ -1074,16 +1041,16 @@
                     userSwitcherComponent.getKeyguardQsUserSwitchController();
             mKeyguardQsUserSwitchController.setNotificationPanelViewController(this);
             mKeyguardQsUserSwitchController.init();
-            mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(true);
+            mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true);
         } else if (keyguardUserSwitcherView != null) {
             KeyguardUserSwitcherComponent userSwitcherComponent =
                     mKeyguardUserSwitcherComponentFactory.build(keyguardUserSwitcherView);
             mKeyguardUserSwitcherController =
                     userSwitcherComponent.getKeyguardUserSwitcherController();
             mKeyguardUserSwitcherController.init();
-            mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(true);
+            mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true);
         } else {
-            mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(false);
+            mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(false);
         }
     }
 
@@ -1142,8 +1109,8 @@
         constraintSet.applyTo(mNotificationContainerParent);
         mNotificationContainerParent.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
 
-        updateKeyguardStatusViewAlignment(false /* animate */);
-        mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
+        updateKeyguardStatusViewAlignment(/* animate= */false);
+
         mKeyguardMediaController.refreshMediaPosition();
     }
 
@@ -1189,6 +1156,9 @@
         keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate(
                 R.layout.keyguard_status_view, mNotificationContainerParent, false);
         mNotificationContainerParent.addView(keyguardStatusView, statusIndex);
+        // When it's reinflated, this is centered by default. If it shouldn't be, this will update
+        // below when resources are updated.
+        mStatusViewCentered = true;
         attachSplitShadeMediaPlayerContainer(
                 keyguardStatusView.findViewById(R.id.status_view_media_container));
 
@@ -1217,8 +1187,7 @@
 
         mBigClockContainer.removeAllViews();
         updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
-                mKeyguardStatusBar, keyguardUserSwitcherView, mCommunalView,
-                mView.findViewById(R.id.idle_host_view));
+                keyguardUserSwitcherView, mView.findViewById(R.id.idle_host_view), mCommunalView);
 
         // Update keyguard bottom area
         int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1358,6 +1327,11 @@
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
         boolean onKeyguard = isOnKeyguard();
+
+        if (onKeyguard) {
+            updateCommunalViewAppearance();
+        }
+
         if (onKeyguard || forceClockUpdate) {
             updateClockAppearance();
         }
@@ -1383,9 +1357,23 @@
         mAnimateNextPositionUpdate = false;
     }
 
+    private void updateCommunalViewAppearance() {
+        if (mCommunalViewController == null) {
+            return;
+        }
+
+        float expandedFraction =
+                mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
+                        ? 1.0f : getExpandedFraction();
+        mCommunalPositionAlgorithm.setup(expandedFraction, mCommunalView.getHeight());
+        mCommunalPositionAlgorithm.run(mCommunalPositionResult);
+        boolean animate =
+                mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending()
+                        || mAnimateNextPositionUpdate;
+        mCommunalViewController.updatePosition(mCommunalPositionResult.communalY, animate);
+    }
+
     private void updateClockAppearance() {
-        int totalHeight = mView.getHeight();
-        int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
         int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
         boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
         final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
@@ -1406,7 +1394,6 @@
                 mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
                         ? 1.0f : mInterpolatedDarkAmount;
         mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
-                totalHeight - bottomPadding,
                 expandedFraction,
                 mKeyguardStatusViewController.getLockscreenHeight(),
                 userIconHeight,
@@ -1415,7 +1402,6 @@
                 bypassEnabled, getUnlockedStackScrollerPadding(),
                 computeQsExpansionFraction(),
                 mDisplayTopInset,
-                mSplitShadeSmartspaceContainer.getHeight(),
                 mShouldUseSplitNotificationShade);
         mClockPositionAlgorithm.run(mClockPositionResult);
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
@@ -1435,9 +1421,6 @@
                     mClockPositionResult.userSwitchY,
                     animateClock);
         }
-        // no need to translate in X axis - horizontal position is determined by constraints
-        mLockscreenSmartspaceController
-                .shiftSplitShadeSmartspace(mClockPositionResult.clockY, animateClock);
         updateNotificationTranslucency();
         updateClock();
     }
@@ -1604,6 +1587,12 @@
         return true;
     }
 
+    private void updateCommunal() {
+        if (mCommunalViewController != null) {
+            mCommunalViewController.setAlpha(mKeyguardOnlyContentAlpha);
+        }
+    }
+
     private void updateClock() {
         float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
         mKeyguardStatusViewController.setAlpha(alpha);
@@ -1613,7 +1602,6 @@
         if (mKeyguardUserSwitcherController != null) {
             mKeyguardUserSwitcherController.setAlpha(alpha);
         }
-        mLockscreenSmartspaceController.setSplitShadeSmartspaceAlpha(alpha);
     }
 
     public void animateToFullShade(long delay) {
@@ -1964,6 +1952,9 @@
 
 
     private boolean handleQsTouch(MotionEvent event) {
+        if (mShouldUseSplitNotificationShade && touchXOutsideOfQs(event.getX())) {
+            return false;
+        }
         final int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
                 && mBarState != KEYGUARD && !mQsExpanded && isQsExpansionEnabled()) {
@@ -2005,8 +1996,12 @@
         return false;
     }
 
+    private boolean touchXOutsideOfQs(float touchX) {
+        return touchX < mQsFrame.getX() || touchX > mQsFrame.getX() + mQsFrame.getWidth();
+    }
+
     private boolean isInQsArea(float x, float y) {
-        if (x < mQsFrame.getX() || x > mQsFrame.getX() + mQsFrame.getWidth()) {
+        if (touchXOutsideOfQs(x)) {
             return false;
         }
         // Let's reject anything at the very bottom around the home handle in gesture nav
@@ -2243,59 +2238,6 @@
         }
     }
 
-    private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mKeyguardStatusBar.setVisibility(View.INVISIBLE);
-            mKeyguardStatusBar.setAlpha(1f);
-            mKeyguardStatusBarAnimateAlpha = 1f;
-        }
-    };
-
-    private void animateKeyguardStatusBarOut() {
-        ValueAnimator anim = ValueAnimator.ofFloat(mKeyguardStatusBar.getAlpha(), 0f);
-        anim.addUpdateListener(mStatusBarAnimateAlphaListener);
-        anim.setStartDelay(mKeyguardStateController.isKeyguardFadingAway()
-                ? mKeyguardStateController.getKeyguardFadingAwayDelay() : 0);
-
-        long duration;
-        if (mKeyguardStateController.isKeyguardFadingAway()) {
-            duration = mKeyguardStateController.getShortenedFadingAwayDuration();
-        } else {
-            duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
-        }
-        anim.setDuration(duration);
-
-        anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimateKeyguardStatusBarInvisibleEndRunnable.run();
-            }
-        });
-        anim.start();
-    }
-
-    private final ValueAnimator.AnimatorUpdateListener
-            mStatusBarAnimateAlphaListener =
-            new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
-                    updateHeaderKeyguardAlpha();
-                }
-            };
-
-    private void animateKeyguardStatusBarIn(long duration) {
-        mKeyguardStatusBar.setVisibility(View.VISIBLE);
-        mKeyguardStatusBar.setAlpha(0f);
-        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
-        anim.addUpdateListener(mStatusBarAnimateAlphaListener);
-        anim.setDuration(duration);
-        anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-        anim.start();
-    }
-
     private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = new Runnable() {
         @Override
         public void run() {
@@ -2348,7 +2290,7 @@
         mQsExpansionHeight = height;
         updateQsExpansion();
         requestScrollerTopPaddingUpdate(false /* animate */);
-        updateHeaderKeyguardAlpha();
+        mKeyguardStatusBarViewController.updateViewState();
         if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) {
             updateKeyguardBottomAreaAlpha();
             positionClockAndNotifications();
@@ -2383,6 +2325,10 @@
         setQSClippingBounds();
         mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
         mDepthController.setQsPanelExpansion(qsExpansionFraction);
+
+        if (mCommunalViewController != null) {
+            mCommunalViewController.updateQsExpansion(qsExpansionFraction);
+        }
     }
 
     private void onStackYChanged(boolean shouldAnimate) {
@@ -2515,7 +2461,6 @@
             boolean qsVisible) {
         // Fancy clipping for quick settings
         int radius = mScrimCornerRadius;
-        int statusBarClipTop = 0;
         boolean clipStatusView = false;
         if (!mShouldUseSplitNotificationShade) {
             // The padding on this area is large enough that we can use a cheaper clipping strategy
@@ -2524,7 +2469,6 @@
             float screenCornerRadius = mRecordingController.isRecording() ? 0 : mScreenCornerRadius;
             radius = (int) MathUtils.lerp(screenCornerRadius, mScrimCornerRadius,
                     Math.min(top / (float) mScrimCornerRadius, 1f));
-            statusBarClipTop = top - mKeyguardStatusBar.getTop();
         }
         if (mQs != null) {
             float qsTranslation = 0;
@@ -2562,8 +2506,13 @@
             mScrimController.setNotificationsBounds(left, top, right, bottom);
         }
 
+        if (mShouldUseSplitNotificationShade) {
+            mKeyguardStatusBarViewController.setNoTopClipping();
+        } else {
+            mKeyguardStatusBarViewController.updateTopClipping(top);
+        }
+
         mScrimController.setScrimCornerRadius(radius);
-        mKeyguardStatusBar.setTopClipping(statusBarClipTop);
         int nsslLeft = left - mNotificationStackScrollLayoutController.getLeft();
         int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
         int nsslTop = top - mNotificationStackScrollLayoutController.getTop();
@@ -2718,6 +2667,10 @@
         }
         mTransitionToFullShadeQSPosition = position;
         updateQsExpansion();
+
+        if (mCommunalViewController != null) {
+            mCommunalViewController.updateShadeExpansion(mTransitioningToFullShadeProgress);
+        }
     }
 
     /**
@@ -2741,6 +2694,7 @@
             updateKeyguardBottomAreaAlpha();
         }
         updateClock();
+        updateCommunal();
     }
 
     private void trackMovement(MotionEvent event) {
@@ -3069,7 +3023,7 @@
      */
     private void updateHeader() {
         if (mBarState == KEYGUARD) {
-            updateHeaderKeyguardAlpha();
+            mKeyguardStatusBarViewController.updateViewState();
         }
         updateQsExpansion();
     }
@@ -3093,47 +3047,6 @@
         return Math.min(0, translation);
     }
 
-    /**
-     * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
-     * during swiping up
-     */
-    private float getKeyguardContentsAlpha() {
-        float alpha;
-        if (mBarState == KEYGUARD) {
-
-            // When on Keyguard, we hide the header as soon as we expanded close enough to the
-            // header
-            alpha =
-                    getExpandedHeight() / (mKeyguardStatusBar.getHeight()
-                            + mNotificationsHeaderCollideDistance);
-        } else {
-
-            // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
-            // soon as we start translating the stack.
-            alpha = getExpandedHeight() / mKeyguardStatusBar.getHeight();
-        }
-        alpha = MathUtils.saturate(alpha);
-        alpha = (float) Math.pow(alpha, 0.75);
-        return alpha;
-    }
-
-    private void updateHeaderKeyguardAlpha() {
-        if (!mKeyguardShowing) {
-            return;
-        }
-        float alphaQsExpansion = 1 - Math.min(1, computeQsExpansionFraction() * 2);
-        float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
-                * mKeyguardStatusBarAnimateAlpha;
-        newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount;
-        mKeyguardStatusBar.setAlpha(newAlpha);
-        boolean
-                hideForBypass =
-                mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace()
-                        || mDelayShowingKeyguardStatusBar;
-        mKeyguardStatusBar.setVisibility(
-                newAlpha != 0f && !mDozing && !hideForBypass ? View.VISIBLE : View.INVISIBLE);
-    }
-
     private void updateKeyguardBottomAreaAlpha() {
         // There are two possible panel expansion behaviors:
         // • User dragging up to unlock: we want to fade out as quick as possible
@@ -3360,7 +3273,7 @@
     private void updateDozingVisibilities(boolean animate) {
         mKeyguardBottomArea.setDozing(mDozing, animate);
         if (!mDozing && animate) {
-            animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
         }
     }
 
@@ -3429,31 +3342,6 @@
         mPanelAlphaEndAction = r;
     }
 
-    private void updateKeyguardStatusBarForHeadsUp() {
-        boolean
-                showingKeyguardHeadsUp =
-                mKeyguardShowing && mHeadsUpAppearanceController.shouldBeVisible();
-        if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
-            mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
-            if (mKeyguardShowing) {
-                PropertyAnimator.setProperty(mView, KEYGUARD_HEADS_UP_SHOWING_AMOUNT,
-                        showingKeyguardHeadsUp ? 1.0f : 0.0f, KEYGUARD_HUN_PROPERTIES,
-                        true /* animate */);
-            } else {
-                PropertyAnimator.applyImmediately(mView, KEYGUARD_HEADS_UP_SHOWING_AMOUNT, 0.0f);
-            }
-        }
-    }
-
-    private void setKeyguardHeadsUpShowingAmount(float amount) {
-        mKeyguardHeadsUpShowingAmount = amount;
-        updateHeaderKeyguardAlpha();
-    }
-
-    private float getKeyguardHeadsUpShowingAmount() {
-        return mKeyguardHeadsUpShowingAmount;
-    }
-
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         mHeadsUpAnimatingAway = headsUpAnimatingAway;
         mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway);
@@ -3756,6 +3644,7 @@
         mDozing = dozing;
         mNotificationStackScrollLayoutController.setDozing(mDozing, animate, wakeUpTouchLocation);
         mKeyguardBottomArea.setDozing(mDozing, animate);
+        mKeyguardStatusBarViewController.setDozing(mDozing);
 
         if (dozing) {
             mBottomAreaShadeAlphaAnimator.cancel();
@@ -3795,7 +3684,6 @@
     public void dozeTimeTick() {
         mKeyguardBottomArea.dozeTimeTick();
         mKeyguardStatusViewController.dozeTimeTick();
-        mLockscreenSmartspaceController.requestSmartspaceUpdate();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
         }
@@ -4018,7 +3906,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;
@@ -4070,6 +3960,7 @@
                     return true;
                 }
                 if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
+                        && !mNotificationStackScrollLayoutController.isLongPressInProgress()
                         && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
                     mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
                 }
@@ -4137,8 +4028,8 @@
         mKeyguardUserSwitcherEnabled = mResources.getBoolean(
                 com.android.internal.R.bool.config_keyguardUserSwitcher);
         mKeyguardQsUserSwitchEnabled =
-                mKeyguardUserSwitcherEnabled && mResources.getBoolean(
-                        R.bool.config_keyguard_user_switch_opens_qs_details);
+                mKeyguardUserSwitcherEnabled
+                        && mFeatureFlags.isKeyguardQsUserDetailsShortcutEnabled();
     }
 
     private void registerSettingsChangeListener() {
@@ -4153,6 +4044,20 @@
         mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
     }
 
+    /**
+     * Updates notification panel-specific flags on {@link SysUiState}.
+     */
+    public void updateSystemUiStateFlags() {
+        if (SysUiState.DEBUG) {
+            Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
+                    + isFullyExpanded() + " inQs=" + isInSettings());
+        }
+        mSysUiState.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+                isFullyExpanded() && !isInSettings())
+                .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED, isInSettings())
+                .commitUpdate(mDisplayId);
+    }
+
     private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
         @Override
         public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -4221,9 +4126,7 @@
         @Override
         public void flingTopOverscroll(float velocity, boolean open) {
             // in split shade mode we want to expand/collapse QS only when touch happens within QS
-            if (mShouldUseSplitNotificationShade
-                    && (mInitialTouchX < mQsFrame.getX()
-                        || mInitialTouchX > mQsFrame.getX() + mQsFrame.getWidth())) {
+            if (mShouldUseSplitNotificationShade && touchXOutsideOfQs(mInitialTouchX)) {
                 return;
             }
             mLastOverscroll = 0f;
@@ -4419,7 +4322,7 @@
             updateGestureExclusionRect();
             mHeadsUpPinnedMode = inPinnedMode;
             updateHeadsUpVisibility();
-            updateKeyguardStatusBarForHeadsUp();
+            mKeyguardStatusBarViewController.updateForHeadsUp();
         }
 
         @Override
@@ -4535,6 +4438,15 @@
                     keyguardFadingAway,
                     goingToFullShade,
                     mBarState);
+
+            if (mCommunalViewController != null) {
+                mCommunalViewController.setKeyguardStatusViewVisibility(
+                        statusBarState,
+                        keyguardFadingAway,
+                        goingToFullShade,
+                        mBarState);
+            }
+
             setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
 
             mBarState = statusBarState;
@@ -4542,11 +4454,22 @@
 
             if (oldState == KEYGUARD && (goingToFullShade
                     || statusBarState == StatusBarState.SHADE_LOCKED)) {
-                animateKeyguardStatusBarOut();
+
+                long startDelay;
+                long duration;
+                if (mKeyguardStateController.isKeyguardFadingAway()) {
+                    startDelay = mKeyguardStateController.getKeyguardFadingAwayDelay();
+                    duration = mKeyguardStateController.getShortenedFadingAwayDuration();
+                } else {
+                    startDelay = 0;
+                    duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
+                }
+                mKeyguardStatusBarViewController.animateKeyguardStatusBarOut(startDelay, duration);
                 updateQSMinHeight();
             } else if (oldState == StatusBarState.SHADE_LOCKED
                     && statusBarState == KEYGUARD) {
-                animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+                mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
+
                 mNotificationStackScrollLayoutController.resetScrollPosition();
                 // Only animate header if the header is visible. If not, it will partially
                 // animate out
@@ -4558,15 +4481,16 @@
                     }
                 }
             } else {
-                mKeyguardStatusBar.setAlpha(1f);
-                mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
+                mKeyguardStatusBarViewController.updateViewState(
+                        /* alpha= */ 1f,
+                        keyguardShowing ? View.VISIBLE : View.INVISIBLE);
                 if (keyguardShowing && oldState != mBarState) {
                     if (mQs != null) {
                         mQs.hideImmediately();
                     }
                 }
             }
-            updateKeyguardStatusBarForHeadsUp();
+            mKeyguardStatusBarViewController.updateForHeadsUp();
             if (keyguardShowing) {
                 updateDozingVisibilities(false /* animate */);
             }
@@ -4592,6 +4516,43 @@
     }
 
     /**
+     * An interface that provides the current state of the notification panel and related views,
+     * which is needed to calculate {@link KeyguardStatusBarView}'s state in
+     * {@link KeyguardStatusBarViewController}.
+     */
+    public interface NotificationPanelViewStateProvider {
+        /** Returns the expanded height of the panel view. */
+        float getPanelViewExpandedHeight();
+        /** Returns the fraction of QS that's expanded. */
+        float getQsExpansionFraction();
+        /**
+         * Returns true if heads up should be visible.
+         *
+         * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into
+         * {@link KeyguardStatusBarViewController} and remove this method.
+         */
+        boolean shouldHeadsUpBeVisible();
+    }
+
+    private final NotificationPanelViewStateProvider mNotificationPanelViewStateProvider =
+            new NotificationPanelViewStateProvider() {
+                @Override
+                public float getPanelViewExpandedHeight() {
+                    return getExpandedHeight();
+                }
+
+                @Override
+                public float getQsExpansionFraction() {
+                    return computeQsExpansionFraction();
+                }
+
+                @Override
+                public boolean shouldHeadsUpBeVisible() {
+                    return mHeadsUpAppearanceController.shouldBeVisible();
+                }
+            };
+
+    /**
      * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
      * screen off animation controller in order to animate in AOD without "actually" fully switching
      * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
@@ -4644,7 +4605,6 @@
                             .addTagListener(QS.TAG, mFragmentListener);
             mStatusBarStateController.addCallback(mStatusBarStateListener);
             mConfigurationController.addCallback(mConfigurationListener);
-            mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
             mCommunalSourceMonitor.addCallback(mCommunalSourceMonitorCallback);
             // Theme might have changed between inflating this view and attaching it to the
             // window, so
@@ -4653,6 +4613,7 @@
             mFalsingManager.addTapListener(mFalsingTapListener);
             mKeyguardIndicationController.init();
             registerSettingsChangeListener();
+            mCommunalStateController.addCallback(mCommunalStateCallback);
         }
 
         @Override
@@ -4662,11 +4623,9 @@
                             .removeTagListener(QS.TAG, mFragmentListener);
             mStatusBarStateController.removeCallback(mStatusBarStateListener);
             mConfigurationController.removeCallback(mConfigurationListener);
-            mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
             mCommunalSourceMonitor.removeCallback(mCommunalSourceMonitorCallback);
-            // Clear source when detached.
-            setCommunalSource(null /*source*/);
             mFalsingManager.removeTapListener(mFalsingTapListener);
+            mCommunalStateController.removeCallback(mCommunalStateCallback);
         }
     }
 
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 d2a4a00..e1cb9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -27,16 +27,20 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
+import android.graphics.Region;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.Trace;
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.IWindow;
+import android.view.IWindowSession;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
@@ -84,8 +88,8 @@
     private final WindowManager mWindowManager;
     private final IActivityManager mActivityManager;
     private final DozeParameters mDozeParameters;
+    private final KeyguardStateController mKeyguardStateController;
     private final LayoutParams mLpChanged;
-    private final boolean mKeyguardScreenRotation;
     private final long mLockScreenDisplayTimeout;
     private final float mKeyguardPreferredRefreshRate; // takes precedence over max
     private final float mKeyguardMaxRefreshRate;
@@ -123,8 +127,8 @@
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
-        mKeyguardScreenRotation = keyguardStateController.isKeyguardScreenRotationAllowed();
         mDozeParameters = dozeParameters;
+        mKeyguardStateController = keyguardStateController;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
         mLpChanged = new LayoutParams();
         mKeyguardViewMediator = keyguardViewMediator;
@@ -323,7 +327,7 @@
 
     private void adjustScreenOrientation(State state) {
         if (state.isKeyguardShowingAndNotOccluded() || state.mDozing) {
-            if (mKeyguardScreenRotation) {
+            if (mKeyguardStateController.isKeyguardScreenRotationAllowed()) {
                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
             } else {
                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
@@ -507,6 +511,19 @@
     }
 
     @Override
+    public void setTouchExclusionRegion(Region region) {
+        try {
+            final IWindowSession session = WindowManagerGlobal.getWindowSession();
+            session.updateTapExcludeRegion(
+                    IWindow.Stub.asInterface(getNotificationShadeView().getWindowToken()),
+                    region);
+        } catch (RemoteException e) {
+            Log.e(TAG, "could not update the tap exclusion region:" + e);
+        }
+    }
+
+
+    @Override
     public void setKeyguardShowing(boolean showing) {
         mCurrentState.mKeyguardShowing = showing;
         apply(mCurrentState);
@@ -606,12 +623,11 @@
     }
 
     @Override
-    public void setLightRevealScrimAmount(float amount) {
-        boolean lightRevealScrimOpaque = amount == 0;
-        if (mCurrentState.mLightRevealScrimOpaque == lightRevealScrimOpaque) {
+    public void setLightRevealScrimOpaque(boolean opaque) {
+        if (mCurrentState.mLightRevealScrimOpaque == opaque) {
             return;
         }
-        mCurrentState.mLightRevealScrimOpaque = lightRevealScrimOpaque;
+        mCurrentState.mLightRevealScrimOpaque = opaque;
         apply(mCurrentState);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index b5d9bd6..147ebfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -47,7 +47,6 @@
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -106,7 +105,7 @@
     private boolean mExpandingBelowNotch;
     private final DockManager mDockManager;
     private final NotificationPanelViewController mNotificationPanelViewController;
-    private final SuperStatusBarViewFactory mStatusBarViewFactory;
+    private final StatusBarWindowView mStatusBarWindowView;
 
     // Used for determining view / touch intersection
     private int[] mTempLocation = new int[2];
@@ -136,7 +135,7 @@
             NotificationShadeDepthController depthController,
             NotificationShadeWindowView notificationShadeWindowView,
             NotificationPanelViewController notificationPanelViewController,
-            SuperStatusBarViewFactory statusBarViewFactory,
+            StatusBarWindowView statusBarWindowView,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
         mInjectionInflationController = injectionInflationController;
@@ -160,7 +159,7 @@
         mDockManager = dockManager;
         mNotificationPanelViewController = notificationPanelViewController;
         mDepthController = depthController;
-        mStatusBarViewFactory = statusBarViewFactory;
+        mStatusBarWindowView = statusBarWindowView;
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
 
@@ -311,6 +310,12 @@
                     // Capture all touch events in always-on.
                     return true;
                 }
+
+                if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
+                    // capture all touches if the alt auth bouncer is showing
+                    return true;
+                }
+
                 boolean intercept = false;
                 if (mNotificationPanelViewController.isFullyExpanded()
                         && mDragDownHelper.isDragDownEnabled()
@@ -338,6 +343,12 @@
                 if (mStatusBarStateController.isDozing()) {
                     handled = !mService.isPulsing();
                 }
+
+                if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {
+                    // eat the touch
+                    handled = true;
+                }
+
                 if ((mDragDownHelper.isDragDownEnabled() && !handled)
                         || mDragDownHelper.isDraggingDown()) {
                     // we still want to finish our drag down gesture when locking the screen
@@ -465,11 +476,10 @@
 
     public void setStatusBarView(PhoneStatusBarView statusBarView) {
         mStatusBarView = statusBarView;
-        if (statusBarView != null && mStatusBarViewFactory != null) {
+        if (statusBarView != null) {
             mBarTransitions = new PhoneStatusBarTransitions(
                     statusBarView,
-                    mStatusBarViewFactory.getStatusBarWindowView()
-                            .findViewById(R.id.status_bar_container));
+                    mStatusBarWindowView.findViewById(R.id.status_bar_container));
         }
     }
 
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 27f08a8..a3877b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -79,7 +79,6 @@
     protected long mDownTime;
     protected boolean mTouchSlopExceededBeforeDown;
     private float mMinExpandHeight;
-    private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mPanelUpdateWhenAnimatorEnds;
     private boolean mVibrateOnOpening;
     protected boolean mIsLaunchAnimationRunning;
@@ -182,6 +181,7 @@
     protected final KeyguardStateController mKeyguardStateController;
     protected final SysuiStatusBarStateController mStatusBarStateController;
     protected final AmbientState mAmbientState;
+    protected final LockscreenGestureLogger mLockscreenGestureLogger;
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
@@ -217,10 +217,12 @@
             LatencyTracker latencyTracker,
             FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+            LockscreenGestureLogger lockscreenGestureLogger,
             AmbientState ambientState) {
         mAmbientState = ambientState;
         mView = view;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mLockscreenGestureLogger = lockscreenGestureLogger;
         mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
             @Override
             public void onViewAttachedToWindow(View v) {
@@ -1211,10 +1213,14 @@
                 case MotionEvent.ACTION_MOVE:
                     final float h = y - mInitialTouchY;
                     addMovement(event);
-                    if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown) {
+                    final boolean openShadeWithoutHun =
+                            mPanelClosedOnDown && !mCollapsedAndHeadsUpOnDown;
+                    if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown
+                            || openShadeWithoutHun) {
                         float hAbs = Math.abs(h);
                         float touchSlop = getTouchSlop(event);
-                        if ((h < -touchSlop || (mAnimatingOnDown && hAbs > touchSlop))
+                        if ((h < -touchSlop
+                                || ((openShadeWithoutHun || mAnimatingOnDown) && hAbs > touchSlop))
                                 && hAbs > Math.abs(x - mInitialTouchX)) {
                             cancelHeightAnimator();
                             startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
@@ -1227,10 +1233,7 @@
                     mVelocityTracker.clear();
                     break;
             }
-
-            // Finally, if none of the above cases applies, ensure that touches do not get handled
-            // by the contents of a panel that is not showing (a bit of a hack to avoid b/178277858)
-            return (mView.getVisibility() != View.VISIBLE);
+            return false;
         }
 
         @Override
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 70a46b2..88a823c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -287,8 +287,13 @@
     public void panelExpansionChanged(float frac, boolean expanded) {
         super.panelExpansionChanged(frac, expanded);
         updateScrimFraction();
-        if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
-            mBar.getNavigationBarView().onStatusBarPanelStateChanged();
+        if ((frac == 0 || frac == 1)) {
+            if (mBar.getNavigationBarView() != null) {
+                mBar.getNavigationBarView().onStatusBarPanelStateChanged();
+            }
+            if (mBar.getNotificationPanelViewController() != null) {
+                mBar.getNotificationPanelViewController().updateSystemUiStateFlags();
+            }
         }
 
         if (mExpansionChangedListeners != null) {
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 43a8630..4213902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -111,6 +111,20 @@
      */
     private boolean mTransitioningToFullShade;
 
+    /**
+     * Is there currently an unocclusion animation running. Used to avoid bright flickers
+     * of the notification scrim.
+     */
+    private boolean mUnOcclusionAnimationRunning;
+
+    /**
+     * Set whether an unocclusion animation is currently running on the notification panel. Used
+     * to avoid bright flickers of the notification scrim.
+     */
+    public void setUnocclusionAnimationRunning(boolean unocclusionAnimationRunning) {
+        mUnOcclusionAnimationRunning = unocclusionAnimationRunning;
+    }
+
     @IntDef(prefix = {"VISIBILITY_"}, value = {
             TRANSPARENT,
             SEMI_TRANSPARENT,
@@ -388,7 +402,7 @@
         if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
             mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
             scheduleUpdate();
-        } else if ((oldState == ScrimState.AOD  // leaving doze
+        } else if (((oldState == ScrimState.AOD || oldState == ScrimState.PULSING)  // leaving doze
                 && (!mDozeParameters.getAlwaysOn() || mState == ScrimState.UNLOCKED))
                 || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
             // Scheduling a frame isn't enough when:
@@ -436,6 +450,7 @@
 
     public void onExpandingFinished() {
         mTracking = false;
+        setUnocclusionAnimationRunning(false);
     }
 
     @VisibleForTesting
@@ -541,6 +556,8 @@
         if (isNaN(expansionFraction)) {
             return;
         }
+        expansionFraction = Interpolators
+                .getNotificationScrimAlpha(expansionFraction, false /* notification */);
         boolean qsBottomVisible = qsPanelBottomY > 0;
         if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) {
             mQsExpansion = expansionFraction;
@@ -672,6 +689,18 @@
                 mNotificationsTint = mState.getNotifTint();
                 mBehindTint = behindTint;
             }
+
+            // At the end of a launch animation over the lockscreen, the state is either KEYGUARD or
+            // SHADE_LOCKED and this code is called. We have to set the notification alpha to 0
+            // otherwise there is a flicker to its previous value.
+            if (mKeyguardOccluded) {
+                mNotificationsAlpha = 0;
+            }
+            if (mUnOcclusionAnimationRunning && mState == ScrimState.KEYGUARD) {
+                // We're unoccluding the keyguard and don't want to have a bright flash.
+                mNotificationsAlpha = KEYGUARD_SCRIM_ALPHA;
+                mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
+            }
         }
 
         assertAlphasValid();
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 e33c9f8..850b986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -229,7 +229,8 @@
                     ? mKeyguardFadingAwayDuration
                     : StatusBar.FADE_KEYGUARD_DURATION;
 
-            mAnimateChange = !mLaunchingAffordanceWithPreview;
+            boolean fromAod = previousState == AOD || previousState == PULSING;
+            mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod;
 
             mFrontTint = Color.TRANSPARENT;
             mBehindTint = Color.BLACK;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
index edacbe1..768222d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -118,10 +118,6 @@
                     + " flags=" + flags);
         }
 
-        if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
-            getStatusBar().postHideRecentApps();
-        }
-
         // TODO(b/62444020): remove when this bug is fixed
         Log.v(TAG, "NotificationShadeWindow: " + getNotificationShadeWindowView()
                 + " canPanelBeCollapsed(): "
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 0a5fa1e..4b7fe4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -20,8 +20,8 @@
 import com.android.systemui.R
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
 import javax.inject.Inject
@@ -54,11 +54,12 @@
         }
 
     init {
-        val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
-        // battery settings same as in QS icons
-        batteryIcon.setIgnoreTunerUpdates(true)
-        batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
         batteryMeterViewController.init()
+        val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
+
+        // battery settings same as in QS icons
+        batteryMeterViewController.ignoreTunerUpdates()
+        batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
 
         val iconContainer: StatusIconContainer = statusBar.findViewById(R.id.statusIcons)
         iconManager = StatusBarIconController.IconManager(iconContainer, featureFlags)
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 5c443a11..0b688d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -51,6 +51,7 @@
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.app.TaskInfo;
+import android.app.TaskStackBuilder;
 import android.app.UiModeManager;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
@@ -73,7 +74,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -143,6 +143,7 @@
 import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.emergency.EmergencyGesture;
@@ -189,14 +190,15 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.NotificationShelfController;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.PowerButtonReveal;
 import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 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.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -223,10 +225,13 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.unfold.config.UnfoldTransitionConfig;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.concurrency.MessageRouter;
 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;
@@ -242,23 +247,15 @@
 import java.util.concurrent.Executor;
 
 import javax.inject.Named;
-import javax.inject.Provider;
 
 import dagger.Lazy;
 
 /** */
 public class StatusBar extends SystemUI implements
         ActivityStarter,
-        ConfigurationListener,
-        StatusBarStateController.StateListener,
-        LifecycleOwner, BatteryController.BatteryStateChangeCallback,
-        ActivityLaunchAnimator.Callback {
+        LifecycleOwner {
     public static final boolean MULTIUSER_DEBUG = false;
 
-    protected static final int MSG_HIDE_RECENT_APPS = 1020;
-    protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
-    protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
-    protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
     protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
 
     // Should match the values in PhoneWindowManager
@@ -286,8 +283,6 @@
 
     public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
 
-    private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
-    private static final int MSG_CLOSE_PANELS = 1001;
     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
     private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
     // 1020-1040 reserved for BaseStatusBar
@@ -367,13 +362,14 @@
         mWereIconsJustHidden = justHidden;
     }
 
-    void resetHandlerMsg(int msg) {
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
+    void resendMessage(int msg) {
+        mMessageRouter.cancelMessages(msg);
+        mMessageRouter.sendMessage(msg);
     }
 
-    Handler getHandler() {
-        return mHandler;
+    void resendMessage(Object msg) {
+        mMessageRouter.cancelMessages(msg.getClass());
+        mMessageRouter.sendMessage(msg);
     }
 
     int getDisabled1() {
@@ -453,6 +449,7 @@
     private BiometricUnlockController mBiometricUnlockController;
     private final LightBarController mLightBarController;
     private final Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
+    private final LockscreenGestureLogger mLockscreenGestureLogger;
     @Nullable
     protected LockscreenWallpaper mLockscreenWallpaper;
     private final AutoHideController mAutoHideController;
@@ -460,7 +457,6 @@
     private final Point mCurrentDisplaySize = new Point();
 
     protected NotificationShadeWindowView mNotificationShadeWindowView;
-    protected StatusBarWindowView mPhoneStatusBarWindow;
     protected PhoneStatusBarView mStatusBarView;
     private PhoneStatusBarViewController mPhoneStatusBarViewController;
     private AuthRippleController mAuthRippleController;
@@ -492,13 +488,13 @@
     protected NotificationShadeWindowViewController mNotificationShadeWindowViewController;
     private final DozeParameters mDozeParameters;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
-    private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
+    private final StatusBarComponent.Factory mStatusBarComponentFactory;
     private final PluginManager mPluginManager;
     private final Optional<LegacySplitScreen> mSplitScreenOptional;
     private final StatusBarNotificationActivityStarter.Builder
             mStatusBarNotificationActivityStarterBuilder;
     private final ShadeController mShadeController;
-    private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    private final StatusBarWindowView mStatusBarWindowView;
     private final LightsOutNotifController mLightsOutNotifController;
     private final InitController mInitController;
 
@@ -520,6 +516,7 @@
     // settings
     private QSPanelController mQSPanelController;
 
+    private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
     KeyguardIndicationController mKeyguardIndicationController;
 
     private View mReportRejectedTouch;
@@ -528,6 +525,7 @@
 
     private final int[] mAbsPos = new int[2];
 
+    protected final NotificationEntryManager mEntryManager;
     private final NotificationGutsManager mGutsManager;
     private final NotificationLogger mNotificationLogger;
     private final NotificationViewHierarchyManager mViewHierarchyManager;
@@ -538,8 +536,10 @@
     private final UnfoldTransitionConfig mUnfoldTransitionConfig;
     private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    private final MessageRouter mMessageRouter;
     private final WallpaperManager mWallpaperManager;
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    private final TunerService mTunerService;
 
     private final List<ExpansionChangedListener> mExpansionChangedListeners;
 
@@ -567,29 +567,6 @@
     // ensure quick settings is disabled until the current user makes it through the setup wizard
     @VisibleForTesting
     protected boolean mUserSetup = false;
-    private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
-        @Override
-        public void onUserSetupChanged() {
-            final boolean userSetup = mDeviceProvisionedController.isUserSetup(
-                    mDeviceProvisionedController.getCurrentUser());
-            Log.d(TAG, "mUserSetupObserver - DeviceProvisionedListener called for user "
-                    + mDeviceProvisionedController.getCurrentUser());
-            if (MULTIUSER_DEBUG) {
-                Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s",
-                        userSetup, mUserSetup));
-            }
-
-            if (userSetup != mUserSetup) {
-                mUserSetup = userSetup;
-                if (!mUserSetup && mStatusBarView != null)
-                    animateCollapseQuickSettings();
-                if (mNotificationPanelViewController != null) {
-                    mNotificationPanelViewController.setUserSetupComplete(mUserSetup);
-                }
-                updateQsExpansionEnabled();
-            }
-        }
-    };
 
     @VisibleForTesting
     public enum StatusBarUiEvent implements UiEventLogger.UiEventEnum {
@@ -629,7 +606,8 @@
         }
     }
 
-    protected final H mHandler = createHandler();
+    private Handler mMainHandler;
+    private final DelayableExecutor mMainExecutor;
 
     private int mInteractingWindows;
     private @TransitionMode int mStatusBarMode;
@@ -646,33 +624,6 @@
     private final NotificationRemoteInputManager mRemoteInputManager;
     private boolean mWallpaperSupported;
 
-    private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (!mWallpaperSupported) {
-                // Receiver should not have been registered at all...
-                Log.wtf(TAG, "WallpaperManager not supported");
-                return;
-            }
-            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.
-            final boolean supportsAmbientMode = deviceSupportsAodWallpaper
-                    && (info != null && info.supportsAmbientMode());
-
-            mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
-            mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
-        }
-    };
-
-    BroadcastReceiver mTaskbarChangeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            mBubblesOptional.ifPresent(bubbles -> bubbles.onTaskbarChanged(intent.getExtras()));
-        }
-    };
-
     private Runnable mLaunchTransitionEndRunnable;
     private boolean mLaunchCameraWhenFinishedWaking;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
@@ -691,29 +642,7 @@
     private boolean mIsOccluded;
     private boolean mWereIconsJustHidden;
     private boolean mBouncerWasShowingWhenHidden;
-
-    // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
-    // this animation is tied to the scrim for historic reasons.
-    // TODO: notify when keyguard has faded away instead of the scrim.
-    private final ScrimController.Callback mUnlockScrimCallback = new ScrimController
-            .Callback() {
-        @Override
-        public void onFinished() {
-            if (mStatusBarKeyguardViewManager == null) {
-                Log.w(TAG, "Tried to notify keyguard visibility when "
-                        + "mStatusBarKeyguardViewManager was null");
-                return;
-            }
-            if (mKeyguardStateController.isKeyguardFadingAway()) {
-                mStatusBarKeyguardViewManager.onKeyguardFadedAway();
-            }
-        }
-
-        @Override
-        public void onCancelled() {
-            onFinished();
-        }
-    };
+    private boolean mIsLaunchingActivityOverLockscreen;
 
     private final UserSwitcherController mUserSwitcherController;
     private final NetworkController mNetworkController;
@@ -732,36 +661,6 @@
     private boolean mNoAnimationOnNextBarModeChange;
     private final SysuiStatusBarStateController mStatusBarStateController;
 
-    private final KeyguardUpdateMonitorCallback mUpdateCallback =
-            new KeyguardUpdateMonitorCallback() {
-                @Override
-                public void onDreamingStateChanged(boolean dreaming) {
-                    if (dreaming) {
-                        maybeEscalateHeadsUp();
-                    }
-                }
-
-                // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
-                //  KeyguardCoordinator
-                @Override
-                public void onStrongAuthStateChanged(int userId) {
-                    super.onStrongAuthStateChanged(userId);
-                    mNotificationsController.requestNotificationUpdate("onStrongAuthStateChanged");
-                }
-            };
-
-
-    private final FalsingManager.FalsingBeliefListener mFalsingBeliefListener =
-            new FalsingManager.FalsingBeliefListener() {
-                @Override
-                public void onFalse() {
-                    // Hides quick settings, bouncer, and quick-quick settings.
-                    mStatusBarKeyguardViewManager.reset(true);
-                }
-            };
-
-    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
-
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private ActivityLaunchAnimator mActivityLaunchAnimator;
     private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
@@ -780,6 +679,7 @@
     private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
             (extractor, which) -> updateTheme();
 
+
     /**
      * Public constructor for StatusBar.
      *
@@ -803,6 +703,7 @@
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
+            NotificationEntryManager notificationEntryManager,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -832,6 +733,7 @@
             DozeParameters dozeParameters,
             ScrimController scrimController,
             Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            LockscreenGestureLogger lockscreenGestureLogger,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
             PowerManager powerManager,
@@ -839,14 +741,14 @@
             DozeScrimController dozeScrimController,
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
-            Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
+            StatusBarComponent.Factory statusBarComponentFactory,
             PluginManager pluginManager,
             Optional<LegacySplitScreen> splitScreenOptional,
             LightsOutNotifController lightsOutNotifController,
             StatusBarNotificationActivityStarter.Builder
                     statusBarNotificationActivityStarterBuilder,
             ShadeController shadeController,
-            SuperStatusBarViewFactory superStatusBarViewFactory,
+            StatusBarWindowView statusBarWindowView,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             ViewMediatorCallback viewMediatorCallback,
             InitController initController,
@@ -855,6 +757,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            OperatorNameViewController.Factory operatorNameViewControllerFactory,
             PhoneStatusBarPolicy phoneStatusBarPolicy,
             KeyguardIndicationController keyguardIndicationController,
             DemoModeController demoModeController,
@@ -871,9 +774,13 @@
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
             FeatureFlags featureFlags,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+            @Main Handler mainHandler,
+            @Main DelayableExecutor delayableExecutor,
+            @Main MessageRouter messageRouter,
             WallpaperManager wallpaperManager,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Optional<StartingSurface> startingSurfaceOptional) {
+            Optional<StartingSurface> startingSurfaceOptional,
+            TunerService tunerService) {
         super(context);
         mNotificationsController = notificationsController;
         mLightBarController = lightBarController;
@@ -884,6 +791,7 @@
         mKeyguardBypassController = keyguardBypassController;
         mKeyguardStateController = keyguardStateController;
         mHeadsUpManager = headsUpManagerPhone;
+        mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
         mKeyguardIndicationController = keyguardIndicationController;
         mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
         mDynamicPrivacyController = dynamicPrivacyController;
@@ -891,6 +799,7 @@
         mFalsingCollector = falsingCollector;
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
+        mEntryManager = notificationEntryManager;
         mGutsManager = notificationGutsManager;
         mNotificationLogger = notificationLogger;
         mNotificationInterruptStateProvider = notificationInterruptStateProvider;
@@ -922,18 +831,19 @@
         mDozeParameters = dozeParameters;
         mScrimController = scrimController;
         mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
+        mLockscreenGestureLogger = lockscreenGestureLogger;
         mScreenPinningRequest = screenPinningRequest;
         mDozeScrimController = dozeScrimController;
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
         mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
         mVolumeComponent = volumeComponent;
         mCommandQueue = commandQueue;
-        mStatusBarComponentBuilder = statusBarComponentBuilder;
+        mStatusBarComponentFactory = statusBarComponentFactory;
         mPluginManager = pluginManager;
         mSplitScreenOptional = splitScreenOptional;
         mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
         mShadeController = shadeController;
-        mSuperStatusBarViewFactory = superStatusBarViewFactory;
+        mStatusBarWindowView = statusBarWindowView;
         mLightsOutNotifController =  lightsOutNotifController;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mKeyguardViewMediatorCallback = viewMediatorCallback;
@@ -954,8 +864,12 @@
         mStatusBarIconController = statusBarIconController;
         mFeatureFlags = featureFlags;
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+        mMainHandler = mainHandler;
+        mMainExecutor = delayableExecutor;
+        mMessageRouter = messageRouter;
         mWallpaperManager = wallpaperManager;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+        mTunerService = tunerService;
 
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mStartingSurfaceOptional = startingSurfaceOptional;
@@ -970,7 +884,18 @@
                 });
 
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
+
+        // TODO(b/190746471): Find a better home for this.
         DateTimeView.setReceiverHandler(timeTickHandler);
+
+        mMessageRouter.subscribeTo(KeyboardShortcutsMessage.class,
+                data -> toggleKeyboardShortcuts(data.mDeviceId));
+        mMessageRouter.subscribeTo(MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU,
+                id -> dismissKeyboardShortcuts());
+        mMessageRouter.subscribeTo(AnimateExpandSettingsPanelMessage.class,
+                data -> mCommandQueueCallbacks.animateExpandSettingsPanel(data.mSubpanel));
+        mMessageRouter.subscribeTo(MSG_LAUNCH_TRANSITION_TIMEOUT,
+                id -> onLaunchTransitionTimeout());
     }
 
     @Override
@@ -988,7 +913,7 @@
         mKeyguardIndicationController.init();
 
         mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
-        mStatusBarStateController.addCallback(this,
+        mStatusBarStateController.addCallback(mStateListener,
                 SysuiStatusBarStateController.RANK_STATUS_BAR);
 
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
@@ -1100,11 +1025,11 @@
                 mNotificationShadeWindowViewController,
                 mNotificationPanelViewController,
                 mAmbientIndicationContainer);
-        mDozeParameters.addCallback(this::updateLightRevealScrimVisibility);
+        updateLightRevealScrimVisibility();
 
-        mConfigurationController.addCallback(this);
+        mConfigurationController.addCallback(mConfigurationListener);
 
-        mBatteryController.observe(mLifecycle, this);
+        mBatteryController.observe(mLifecycle, mBatteryStateChangeCallback);
         mLifecycle.setCurrentState(RESUMED);
 
         // set the initial view visibility
@@ -1125,7 +1050,7 @@
 
                     @Override
                     public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
-                        mMainThreadHandler.post(
+                        mMainExecutor.execute(
                                 () -> plugin.setup(getNotificationShadeWindowView(),
                                         getNavigationBarView(),
                                         new Callback(plugin), mDozeParameters));
@@ -1133,7 +1058,7 @@
 
                     @Override
                     public void onPluginDisconnected(OverlayPlugin plugin) {
-                        mMainThreadHandler.post(() -> {
+                        mMainExecutor.execute(() -> {
                             mOverlays.remove(plugin);
                             mNotificationShadeWindowController
                                     .setForcePluginOpen(mOverlays.size() != 0, this);
@@ -1154,7 +1079,7 @@
                             } else {
                                 mOverlays.remove(mPlugin);
                             }
-                            mMainThreadHandler.post(() -> {
+                            mMainExecutor.execute(() -> {
                                 mNotificationShadeWindowController
                                         .setStateListener(b -> mOverlays.forEach(
                                                 o -> o.setCollapseDesired(b)));
@@ -1164,6 +1089,11 @@
                         }
                     }
                 }, OverlayPlugin.class, true /* Allow multiple plugins */);
+
+        mStartingSurfaceOptional.ifPresent(startingSurface -> startingSurface.setSysuiProxy(
+                (requestTopUi, componentTag) -> mMainExecutor.execute(() ->
+                        mNotificationShadeWindowController.setRequestTopUi(
+                                requestTopUi, componentTag))));
     }
 
     // ================================================================================
@@ -1180,14 +1110,10 @@
 
         // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
-        mStackScrollerController =
-                mNotificationPanelViewController.getNotificationStackScrollLayoutController();
-        mStackScroller = mStackScrollerController.getView();
         NotificationListContainer notifListContainer =
                 mStackScrollerController.getNotificationListContainer();
         mNotificationLogger.setUpWithContainer(notifListContainer);
 
-        inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelfController);
         mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator);
         mNotificationPanelViewController.addExpansionListener(
@@ -1196,7 +1122,7 @@
         // Allow plugins to reference DarkIconDispatcher and StatusBarStateController
         mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class);
         mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class);
-        FragmentHostManager.get(mPhoneStatusBarWindow)
+        FragmentHostManager.get(mStatusBarWindowView)
                 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                     CollapsedStatusBarFragment statusBarFragment =
                             (CollapsedStatusBarFragment) fragment;
@@ -1207,12 +1133,22 @@
                     mStatusBarView.setPanel(mNotificationPanelViewController);
                     mStatusBarView.setScrimController(mScrimController);
                     mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+                    for (ExpansionChangedListener listener : mExpansionChangedListeners) {
+                        sendInitialExpansionAmount(listener);
+                    }
+
                     mPhoneStatusBarViewController =
                             new PhoneStatusBarViewController(mStatusBarView, mCommandQueue);
                     mPhoneStatusBarViewController.init();
 
                     mBatteryMeterViewController = new BatteryMeterViewController(
-                            mStatusBarView.findViewById(R.id.battery)
+                            mStatusBarView.findViewById(R.id.battery),
+                            mConfigurationController,
+                            mTunerService,
+                            mBroadcastDispatcher,
+                            mMainHandler,
+                            mContext.getContentResolver(),
+                            mBatteryController
                     );
                     mBatteryMeterViewController.init();
 
@@ -1266,7 +1202,8 @@
                                 mNetworkController,
                                 mStatusBarStateController,
                                 () -> Optional.of(this),
-                                mCommandQueue
+                                mCommandQueue,
+                                mOperatorNameViewControllerFactory
                         ),
                         CollapsedStatusBarFragment.TAG)
                 .commit();
@@ -1322,8 +1259,19 @@
         mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront);
 
         mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
-        mLightRevealScrim.setRevealAmountListener(
-                mNotificationShadeWindowController::setLightRevealScrimAmount);
+        mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> {
+            Runnable updateOpaqueness = () -> {
+                mNotificationShadeWindowController.setLightRevealScrimOpaque(
+                        mLightRevealScrim.isScrimOpaque());
+            };
+            if (opaque) {
+                // Delay making the view opaque for a frame, because it needs some time to render
+                // otherwise this can lead to a flicker where the scrim doesn't cover the screen
+                mLightRevealScrim.post(updateOpaqueness);
+            } else {
+                updateOpaqueness.run();
+            }
+        });
         mUnlockedScreenOffAnimationController.initialize(this, mLightRevealScrim);
         updateLightRevealScrimVisibility();
 
@@ -1466,19 +1414,6 @@
         return mLifecycle;
     }
 
-    @Override
-    public void onPowerSaveChanged(boolean isPowerSave) {
-        mHandler.post(mCheckBarModes);
-        if (mDozeServiceHost != null) {
-            mDozeServiceHost.firePowerSaveChanged(isPowerSave);
-        }
-    }
-
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        // noop
-    }
-
     @VisibleForTesting
     protected void registerBroadcastReceiver() {
         IntentFilter filter = new IntentFilter();
@@ -1494,7 +1429,7 @@
 
     private void setUpPresenter() {
         // Set up the initial notification state.
-        mActivityLaunchAnimator = new ActivityLaunchAnimator(this, mContext);
+        mActivityLaunchAnimator = new ActivityLaunchAnimator(mKeyguardHandler, mContext);
         mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
                 mNotificationShadeWindowViewController,
                 mStackScrollerController.getNotificationListContainer(),
@@ -1502,14 +1437,34 @@
         );
 
         // TODO: inject this.
-        mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
-                mHeadsUpManager, mNotificationShadeWindowView, mStackScrollerController,
-                mDozeScrimController, mScrimController, mNotificationShadeWindowController,
-                mDynamicPrivacyController, mKeyguardStateController,
+        mPresenter = new StatusBarNotificationPresenter(
+                mContext,
+                mNotificationPanelViewController,
+                mHeadsUpManager,
+                mNotificationShadeWindowView,
+                mStackScrollerController,
+                mDozeScrimController,
+                mScrimController,
+                mNotificationShadeWindowController,
+                mDynamicPrivacyController,
+                mKeyguardStateController,
                 mKeyguardIndicationController,
-                this /* statusBar */, mShadeController,
-                mLockscreenShadeTransitionController, mCommandQueue, mInitController,
-                mNotificationInterruptStateProvider);
+                this /* statusBar */,
+                mShadeController,
+                mLockscreenShadeTransitionController,
+                mCommandQueue,
+                mViewHierarchyManager,
+                mLockscreenUserManager,
+                mStatusBarStateController,
+                mEntryManager,
+                mMediaManager,
+                mGutsManager,
+                mKeyguardUpdateMonitor,
+                mLockscreenGestureLogger,
+                mInitController,
+                mNotificationInterruptStateProvider,
+                mRemoteInputManager,
+                mConfigurationController);
 
         mNotificationShelfController.setOnActivatedListener(mPresenter);
         mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
@@ -1585,66 +1540,20 @@
         };
     }
 
-    private void inflateShelf() {
-        mNotificationShelfController = mSuperStatusBarViewFactory
-                .getNotificationShelfController(mStackScroller);
-    }
-
-    @Override
-    public void onDensityOrFontScaleChanged() {
-        // TODO: Remove this.
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.onDensityOrFontScaleChanged();
-        }
-        // TODO: Bring these out of StatusBar.
-        mUserInfoControllerImpl.onDensityOrFontScaleChanged();
-        mUserSwitcherController.onDensityOrFontScaleChanged();
-        mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
-        mHeadsUpManager.onDensityOrFontScaleChanged();
-    }
-
-    @Override
-    public void onThemeChanged() {
-        if (mStatusBarKeyguardViewManager != null) {
-            mStatusBarKeyguardViewManager.onThemeChanged();
-        }
-        if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
-            ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
-        }
-        mNotificationIconAreaController.onThemeChanged();
-    }
-
-    @Override
-    public void onOverlayChanged() {
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.onOverlayChanged();
-        }
-        // We need the new R.id.keyguard_indication_area before recreating
-        // mKeyguardIndicationController
-        mNotificationPanelViewController.onThemeChanged();
-        onThemeChanged();
-    }
-
-    @Override
-    public void onUiModeChanged() {
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.onUiModeChanged();
-        }
-    }
-
     private void inflateStatusBarWindow() {
-        mNotificationShadeWindowView = mSuperStatusBarViewFactory.getNotificationShadeWindowView();
-        StatusBarComponent statusBarComponent = mStatusBarComponentBuilder.get()
-                .statusBarWindowView(mNotificationShadeWindowView).build();
+        StatusBarComponent statusBarComponent = mStatusBarComponentFactory.create();
+        mNotificationShadeWindowView = statusBarComponent.getNotificationShadeWindowView();
         mNotificationShadeWindowViewController = statusBarComponent
                 .getNotificationShadeWindowViewController();
         mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
         mNotificationShadeWindowViewController.setupExpandedStatusBar();
         mStatusBarWindowController = statusBarComponent.getStatusBarWindowController();
-        mPhoneStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
         mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
         statusBarComponent.getLockIconViewController().init();
+        mStackScrollerController = statusBarComponent.getNotificationStackScrollLayoutController();
+        mStackScroller = mStackScrollerController.getView();
 
+        mNotificationShelfController = statusBarComponent.getNotificationShelfController();
         mAuthRippleController = statusBarComponent.getAuthRippleController();
         mAuthRippleController.init();
 
@@ -1719,7 +1628,7 @@
     }
 
     public StatusBarWindowView getStatusBarWindow() {
-        return mPhoneStatusBarWindow;
+        return mStatusBarWindowView;
     }
 
     public NotificationShadeWindowViewController getNotificationShadeWindowViewController() {
@@ -1731,7 +1640,7 @@
     }
 
     protected ViewGroup getBouncerContainer() {
-        return mNotificationShadeWindowView;
+        return mNotificationShadeWindowView.findViewById(R.id.keyboard_bouncer_container);
     }
 
     public int getStatusBarHeight() {
@@ -1817,10 +1726,6 @@
         return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
     }
 
-    protected H createHandler() {
-        return new StatusBar.H();
-    }
-
     @Override
     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
             int flags) {
@@ -1834,10 +1739,77 @@
 
     @Override
     public void startActivity(Intent intent, boolean dismissShade,
-            ActivityLaunchAnimator.Controller animationController) {
-        startActivityDismissingKeyguard(intent, false, dismissShade,
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            boolean showOverLockscreenWhenLocked) {
+        // Make sure that we dismiss the keyguard if it is directly dismissable or when we don't
+        // want to show the activity above it.
+        if (mKeyguardStateController.isUnlocked() || !showOverLockscreenWhenLocked) {
+            startActivityDismissingKeyguard(intent, false, dismissShade,
                 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
                 0 /* flags */, animationController);
+            return;
+        }
+
+        boolean animate =
+                animationController != null && shouldAnimateLaunch(true /* isActivityIntent */,
+                        showOverLockscreenWhenLocked);
+
+        ActivityLaunchAnimator.Controller controller = null;
+        if (animate) {
+            // Wrap the animation controller to dismiss the shade and set
+            // mIsLaunchingActivityOverLockscreen during the animation.
+            ActivityLaunchAnimator.Controller delegate = wrapAnimationController(
+                    animationController, dismissShade);
+            controller = new DelegateLaunchAnimatorController(delegate) {
+                @Override
+                public void onIntentStarted(boolean willAnimate) {
+                    getDelegate().onIntentStarted(willAnimate);
+
+                    if (willAnimate) {
+                        StatusBar.this.mIsLaunchingActivityOverLockscreen = true;
+                    }
+                }
+
+                @Override
+                public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
+                    // Set mIsLaunchingActivityOverLockscreen to false before actually finishing the
+                    // animation so that we can assume that mIsLaunchingActivityOverLockscreen
+                    // being true means that we will collapse the shade (or at least run the
+                    // post collapse runnables) later on.
+                    StatusBar.this.mIsLaunchingActivityOverLockscreen = false;
+                    getDelegate().onLaunchAnimationEnd(isExpandingFullyAbove);
+                }
+
+                @Override
+                public void onLaunchAnimationCancelled() {
+                    // Set mIsLaunchingActivityOverLockscreen to false before actually finishing the
+                    // animation so that we can assume that mIsLaunchingActivityOverLockscreen
+                    // being true means that we will collapse the shade (or at least run the
+                    // post collapse runnables) later on.
+                    StatusBar.this.mIsLaunchingActivityOverLockscreen = false;
+                    getDelegate().onLaunchAnimationCancelled();
+                }
+            };
+        } else if (dismissShade) {
+            // The animation will take care of dismissing the shade at the end of the animation. If
+            // we don't animate, collapse it directly.
+            collapseShade();
+        }
+
+        mActivityLaunchAnimator.startIntentWithAnimation(controller, animate,
+                intent.getPackage(), showOverLockscreenWhenLocked, (adapter) -> TaskStackBuilder
+                        .create(mContext)
+                        .addNextIntent(intent)
+                        .startActivities(getActivityOptions(getDisplayId(), adapter),
+                                UserHandle.CURRENT));
+    }
+
+    /**
+     * Whether we are currently animating an activity launch above the lockscreen (occluding
+     * activity).
+     */
+    public boolean isLaunchingActivityOverLockscreen() {
+        return mIsLaunchingActivityOverLockscreen;
     }
 
     @Override
@@ -1857,6 +1829,7 @@
         mNotificationPanelViewController.setStatusAccessibilityImportance(expanded
                 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        mNotificationPanelViewController.updateSystemUiStateFlags();
         if (getNavigationBarView() != null) {
             getNavigationBarView().onStatusBarPanelStateChanged();
         }
@@ -1955,7 +1928,7 @@
                 // We're delaying the showing, since most of the time the fullscreen app will
                 // hide the icons again and we don't want them to fade in and out immediately again.
                 mWereIconsJustHidden = true;
-                mHandler.postDelayed(() -> {
+                mMainExecutor.executeDelayed(() -> {
                     mWereIconsJustHidden = false;
                     mCommandQueue.recomputeDisableFlags(mDisplayId, true);
                 }, 500);
@@ -1998,51 +1971,28 @@
      *
      * Note: This method must be called *before* dismissing the keyguard.
      */
-    public boolean shouldAnimateLaunch(boolean isActivityIntent) {
+    public boolean shouldAnimateLaunch(boolean isActivityIntent, boolean showOverLockscreen) {
         // TODO(b/184121838): Support launch animations when occluded.
         if (isOccluded()) {
             return false;
         }
 
-        // Always animate if we are unlocked.
-        if (!mKeyguardStateController.isShowing()) {
+        // Always animate if we are not showing the keyguard or if we animate over the lockscreen
+        // (without unlocking it).
+        if (showOverLockscreen || !mKeyguardStateController.isShowing()) {
             return true;
         }
 
-        // If we are locked, only animate if remote unlock animations are enabled. We also don't
-        // animate non-activity launches as they can break the animation.
+        // If we are locked and have to dismiss the keyguard, only animate if remote unlock
+        // animations are enabled. We also don't animate non-activity launches as they can break the
+        // animation.
         // TODO(b/184121838): Support non activity launches on the lockscreen.
         return isActivityIntent && KeyguardService.sEnableRemoteKeyguardGoingAwayAnimation;
     }
 
-    @Override
-    public boolean isOnKeyguard() {
-        return mKeyguardStateController.isShowing();
-    }
-
-    @Override
-    public void hideKeyguardWithAnimation(IRemoteAnimationRunner runner) {
-        // We post to the main thread for 2 reasons:
-        //   1. KeyguardViewMediator is not thread-safe.
-        //   2. To ensure that ViewMediatorCallback#keyguardDonePending is called before
-        //      ViewMediatorCallback#readyForKeyguardDone. The wrong order could occur when doing
-        //      dismissKeyguardThenExecute { hideKeyguardWithAnimation(runner) }.
-        mMainThreadHandler.post(() -> mKeyguardViewMediator.hideWithAnimation(runner));
-    }
-
-    @Override
-    public void setBlursDisabledForAppLaunch(boolean disabled) {
-        mKeyguardViewMediator.setBlursDisabledForAppLaunch(disabled);
-    }
-
-    @Override
-    public int getBackgroundColor(TaskInfo task) {
-        if (!mStartingSurfaceOptional.isPresent()) {
-            Log.w(TAG, "No starting surface, defaulting to SystemBGColor");
-            return SplashscreenContentDrawer.getSystemBGColor();
-        }
-
-        return mStartingSurfaceOptional.get().getBackgroundColor(task);
+    /** Whether we should animate an activity launch. */
+    public boolean shouldAnimateLaunch(boolean isActivityIntent) {
+        return shouldAnimateLaunch(isActivityIntent, false /* showOverLockscreen */);
     }
 
     public boolean isDeviceInVrMode() {
@@ -2058,37 +2008,19 @@
         mState = state;
     }
 
-    /**
-     * All changes to the status bar and notifications funnel through here and are batched.
-     */
-    protected class H extends Handler {
-        H() {
-            super(Looper.myLooper());
-        }
+    static class KeyboardShortcutsMessage {
+        final int mDeviceId;
 
-        @Override
-        public void handleMessage(Message m) {
-            switch (m.what) {
-                case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
-                    toggleKeyboardShortcuts(m.arg1);
-                    break;
-                case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
-                    dismissKeyboardShortcuts();
-                    break;
-                // End old BaseStatusBar.H handling.
-                case MSG_OPEN_NOTIFICATION_PANEL:
-                    mCommandQueueCallbacks.animateExpandNotificationsPanel();
-                    break;
-                case MSG_OPEN_SETTINGS_PANEL:
-                    mCommandQueueCallbacks.animateExpandSettingsPanel((String) m.obj);
-                    break;
-                case MSG_CLOSE_PANELS:
-                    mShadeController.animateCollapsePanels();
-                    break;
-                case MSG_LAUNCH_TRANSITION_TIMEOUT:
-                    onLaunchTransitionTimeout();
-                    break;
-            }
+        KeyboardShortcutsMessage(int deviceId) {
+            mDeviceId = deviceId;
+        }
+    }
+
+    static class AnimateExpandSettingsPanelMessage {
+        final String mSubpanel;
+
+        AnimateExpandSettingsPanelMessage(String subpanel) {
+            mSubpanel = subpanel;
         }
     }
 
@@ -2130,27 +2062,17 @@
     }
 
     public void postAnimateCollapsePanels() {
-        mHandler.post(mShadeController::animateCollapsePanels);
+        mMainExecutor.execute(mShadeController::animateCollapsePanels);
     }
 
     public void postAnimateForceCollapsePanels() {
-        mHandler.post(() -> mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE,
+        mMainExecutor.execute(
+                () -> mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE,
                 true /* force */));
     }
 
     public void postAnimateOpenPanels() {
-        mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
-    }
-
-    /**
-     * Called by {@link ShadeController} when it calls
-     * {@link ShadeController#animateCollapsePanels(int, boolean, boolean, float)}.
-     */
-    void postHideRecentApps() {
-        if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
-            mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
-            mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
-        }
+        mMessageRouter.sendMessage(MSG_OPEN_SETTINGS_PANEL);
     }
 
     public boolean isExpandedVisible() {
@@ -2620,7 +2542,7 @@
                             options.setRotationAnimationHint(
                                     WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
                         }
-                        if (intent.getAction().equals(Settings.Panel.ACTION_VOLUME)) {
+                        if (Settings.Panel.ACTION_VOLUME.equals(intent.getAction())) {
                             // Settings Panel is implemented as activity(not a dialog), so
                             // underlying app is paused and may enter picture-in-picture mode
                             // as a result.
@@ -2660,7 +2582,7 @@
     private ActivityLaunchAnimator.Controller wrapAnimationController(
             ActivityLaunchAnimator.Controller animationController, boolean dismissShade) {
         View rootView = animationController.getLaunchContainer().getRootView();
-        if (rootView == mSuperStatusBarViewFactory.getStatusBarWindowView()) {
+        if (rootView == mStatusBarWindowView) {
             // We are animating a view in the status bar. We have to make sure that the status bar
             // window matches the full screen during the animation and that we are expanding the
             // view below the other status bar text.
@@ -2719,7 +2641,7 @@
                             && mStatusBarKeyguardViewManager.isOccluded()) {
                         mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
                     } else {
-                        mHandler.post(runnable);
+                        mMainExecutor.execute(runnable);
                     }
                 }
                 if (dismissShade) {
@@ -2731,7 +2653,7 @@
 
                         // Do it after DismissAction has been processed to conserve the needed
                         // ordering.
-                        mHandler.post(mShadeController::runPostCollapseRunnables);
+                        mMainExecutor.execute(mShadeController::runPostCollapseRunnables);
                     }
                 } else if (StatusBar.this.isInLaunchTransition()
                         && mNotificationPanelViewController.isLaunchTransitionFinished()) {
@@ -2740,7 +2662,7 @@
                     // finished,
                     // so nobody will call readyForKeyguardDone anymore. Post it such that
                     // keyguardDonePending gets called first.
-                    mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone);
+                    mMainExecutor.execute(mStatusBarKeyguardViewManager::readyForKeyguardDone);
                 }
                 return deferred;
             }
@@ -2779,8 +2701,8 @@
                     mNotificationShadeWindowController.setNotTouchable(false);
                 }
                 if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
-                    // Post to main thread handler, since updating the UI.
-                    mMainThreadHandler.post(() -> mBubblesOptional.get().collapseStack());
+                    // Post to main thread, since updating the UI.
+                    mMainExecutor.execute(() -> mBubblesOptional.get().collapseStack());
                 }
                 finishBarAnimations();
                 resetUserExpandedStates();
@@ -2841,20 +2763,6 @@
             action.onDismiss();
         }
     }
-
-    @Override
-    public void onConfigChanged(Configuration newConfig) {
-        updateResources();
-        updateDisplaySize(); // populates mDisplayMetrics
-
-        if (DEBUG) {
-            Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
-        }
-
-        mViewHierarchyManager.updateRowStates();
-        mScreenPinningRequest.onConfigurationChanged();
-    }
-
     /**
      * Notify the shade controller that the current user changed
      *
@@ -3004,10 +2912,10 @@
 
     @Override
     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
-        mHandler.post(() -> {
+        mMainExecutor.execute(() -> {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
-            executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false,
-                    false);
+            executeRunnableDismissingKeyguard(
+                    () -> mMainExecutor.execute(runnable), null, false, false, false);
         });
     }
 
@@ -3019,7 +2927,7 @@
     @Override
     public void postStartActivityDismissingKeyguard(final PendingIntent intent,
             @Nullable ActivityLaunchAnimator.Controller animationController) {
-        mHandler.post(() -> startPendingIntentDismissingKeyguard(intent,
+        mMainExecutor.execute(() -> startPendingIntentDismissingKeyguard(intent,
                 null /* intentSentUiThreadCallback */, animationController));
     }
 
@@ -3031,7 +2939,7 @@
     @Override
     public void postStartActivityDismissingKeyguard(Intent intent, int delay,
             @Nullable ActivityLaunchAnimator.Controller animationController) {
-        mHandler.postDelayed(
+        mMainExecutor.executeDelayed(
                 () ->
                         startActivityDismissingKeyguard(intent, true /* onlyProvisioned */,
                                 true /* dismissShade */,
@@ -3101,7 +3009,7 @@
             mNotificationPanelViewController.cancelAnimation();
             onLaunchTransitionFadingEnded();
         }
-        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
+        mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
             mStatusBarStateController.setState(StatusBarState.FULLSCREEN_USER_SWITCHER);
         } else if (!mPulseExpansionHandler.isWakingToShadeLocked()) {
@@ -3142,7 +3050,7 @@
      */
     public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
             Runnable endRunnable) {
-        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
+        mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         mLaunchTransitionEndRunnable = endRunnable;
         Runnable hideRunnable = () -> {
             mKeyguardStateController.setLaunchTransitionFadingAway(true);
@@ -3183,6 +3091,7 @@
     public void animateKeyguardUnoccluding() {
         mNotificationPanelViewController.setExpandedFraction(0f);
         mCommandQueueCallbacks.animateExpandNotificationsPanel();
+        mScrimController.setUnocclusionAnimationRunning(true);
     }
 
     /**
@@ -3191,8 +3100,8 @@
      * because the launched app crashed or something else went wrong.
      */
     public void startLaunchTransitionTimeout() {
-        mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
-                LAUNCH_TRANSITION_TIMEOUT_MS);
+        mMessageRouter.sendMessageDelayed(
+                MSG_LAUNCH_TRANSITION_TIMEOUT, LAUNCH_TRANSITION_TIMEOUT_MS);
     }
 
     private void onLaunchTransitionTimeout() {
@@ -3247,7 +3156,7 @@
         if (mQSPanelController != null) {
             mQSPanelController.refreshAllTiles();
         }
-        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
+        mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         releaseGestureWakeLock();
         mNotificationPanelViewController.onAffordanceLaunchEnded();
         mNotificationPanelViewController.cancelAnimation();
@@ -3475,69 +3384,7 @@
         mNotificationPanelViewController.collapseWithDuration(duration);
     }
 
-    @Override
-    public void onStatePreChange(int oldState, int newState) {
-        // If we're visible and switched to SHADE_LOCKED (the user dragged
-        // down on the lockscreen), clear notification LED, vibration,
-        // ringing.
-        // Other transitions are covered in handleVisibleToUserChanged().
-        if (mVisible && (newState == StatusBarState.SHADE_LOCKED
-                || mStatusBarStateController.goingToFullShade())) {
-            clearNotificationEffects();
-        }
-        if (newState == StatusBarState.KEYGUARD) {
-            mRemoteInputManager.onPanelCollapsed();
-            maybeEscalateHeadsUp();
-        }
-    }
 
-    @Override
-    public void onStateChanged(int newState) {
-        mState = newState;
-        updateReportRejectedTouchVisibility();
-        mDozeServiceHost.updateDozing();
-        updateTheme();
-        mNavigationBarController.touchAutoDim(mDisplayId);
-        Trace.beginSection("StatusBar#updateKeyguardState");
-        if (mState == StatusBarState.KEYGUARD && mStatusBarView != null) {
-            mStatusBarView.removePendingHideExpandedRunnables();
-        }
-        updateDozingState();
-        checkBarModes();
-        updateScrimController();
-        mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
-        updateKeyguardState();
-        Trace.endSection();
-    }
-
-    @Override
-    public void onDozeAmountChanged(float linear, float eased) {
-        if (mFeatureFlags.useNewLockscreenAnimations()
-                && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
-            mLightRevealScrim.setRevealAmount(1f - linear);
-        }
-    }
-
-    @Override
-    public void onDozingChanged(boolean isDozing) {
-        Trace.beginSection("StatusBar#updateDozing");
-        mDozing = isDozing;
-
-        // Collapse the notification panel if open
-        boolean dozingAnimated = mDozeServiceHost.getDozingRequested()
-                && mDozeParameters.shouldControlScreenOff();
-        mNotificationPanelViewController.resetViews(dozingAnimated);
-
-        updateQsExpansionEnabled();
-        mKeyguardViewMediator.setDozing(mDozing);
-
-        mNotificationsController.requestNotificationUpdate("onDozingChanged");
-        updateDozingState();
-        mDozeServiceHost.updateDozing();
-        updateScrimController();
-        updateReportRejectedTouchVisibility();
-        Trace.endSection();
-    }
 
     /**
      * Updates the light reveal effect to reflect the reason we're waking or sleeping (for example,
@@ -3679,7 +3526,7 @@
 
                 // This gets executed before we will show Keyguard, so post it in order that the state
                 // is correct.
-                mHandler.post(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected(
+                mMainExecutor.execute(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected(
                         mLastCameraLaunchSource));
             }
 
@@ -3688,7 +3535,7 @@
 
                 // This gets executed before we will show Keyguard, so post it in order that the
                 // state is correct.
-                mHandler.post(
+                mMainExecutor.execute(
                         () -> mCommandQueueCallbacks.onEmergencyActionLaunchGestureDetected());
             }
             updateIsKeyguard();
@@ -3908,10 +3755,8 @@
             ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
                     ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
             mScrimController.transitionTo(state);
-        } else if (isInLaunchTransition()
-                || mLaunchCameraWhenFinishedWaking
-                || launchingAffordanceWithPreview) {
-            // TODO(b/170133395) Investigate whether Emergency Gesture flag should be included here.
+        } else if (launchingAffordanceWithPreview) {
+            // We want to avoid animating when launching with a preview.
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
@@ -4157,7 +4002,7 @@
     }
 
     private void postOnUiThread(Runnable runnable) {
-        mMainThreadHandler.post(runnable);
+        mMainExecutor.execute(runnable);
     }
 
     /**
@@ -4315,6 +4160,14 @@
 
     public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
         mExpansionChangedListeners.add(listener);
+        sendInitialExpansionAmount(listener);
+    }
+
+    private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
+        if (mStatusBarView != null) {
+            expansionChangedListener.onExpansionChanged(mStatusBarView.getExpansionFraction(),
+                    mStatusBarView.isExpanded());
+        }
     }
 
     public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
@@ -4328,11 +4181,278 @@
         }
 
         mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
-        if (mFeatureFlags.useNewLockscreenAnimations()
-                && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
-            mLightRevealScrim.setVisibility(View.VISIBLE);
-        } else {
-            mLightRevealScrim.setVisibility(View.GONE);
-        }
     }
+
+    private final KeyguardUpdateMonitorCallback mUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onDreamingStateChanged(boolean dreaming) {
+                    if (dreaming) {
+                        maybeEscalateHeadsUp();
+                    }
+                }
+
+                // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+                //  KeyguardCoordinator
+                @Override
+                public void onStrongAuthStateChanged(int userId) {
+                    super.onStrongAuthStateChanged(userId);
+                    mNotificationsController.requestNotificationUpdate("onStrongAuthStateChanged");
+                }
+            };
+
+
+    private final FalsingManager.FalsingBeliefListener mFalsingBeliefListener =
+            new FalsingManager.FalsingBeliefListener() {
+                @Override
+                public void onFalse() {
+                    // Hides quick settings, bouncer, and quick-quick settings.
+                    mStatusBarKeyguardViewManager.reset(true);
+                }
+            };
+
+    // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
+    // this animation is tied to the scrim for historic reasons.
+    // TODO: notify when keyguard has faded away instead of the scrim.
+    private final ScrimController.Callback mUnlockScrimCallback = new ScrimController
+            .Callback() {
+        @Override
+        public void onFinished() {
+            if (mStatusBarKeyguardViewManager == null) {
+                Log.w(TAG, "Tried to notify keyguard visibility when "
+                        + "mStatusBarKeyguardViewManager was null");
+                return;
+            }
+            if (mKeyguardStateController.isKeyguardFadingAway()) {
+                mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+            }
+        }
+
+        @Override
+        public void onCancelled() {
+            onFinished();
+        }
+    };
+
+    private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
+        @Override
+        public void onUserSetupChanged() {
+            final boolean userSetup = mDeviceProvisionedController.isUserSetup(
+                    mDeviceProvisionedController.getCurrentUser());
+            Log.d(TAG, "mUserSetupObserver - DeviceProvisionedListener called for user "
+                    + mDeviceProvisionedController.getCurrentUser());
+            if (MULTIUSER_DEBUG) {
+                Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s",
+                        userSetup, mUserSetup));
+            }
+
+            if (userSetup != mUserSetup) {
+                mUserSetup = userSetup;
+                if (!mUserSetup && mStatusBarView != null) {
+                    animateCollapseQuickSettings();
+                }
+                if (mNotificationPanelViewController != null) {
+                    mNotificationPanelViewController.setUserSetupComplete(mUserSetup);
+                }
+                updateQsExpansionEnabled();
+            }
+        }
+    };
+
+    private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mWallpaperSupported) {
+                // Receiver should not have been registered at all...
+                Log.wtf(TAG, "WallpaperManager not supported");
+                return;
+            }
+            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.
+            final boolean supportsAmbientMode = deviceSupportsAodWallpaper
+                    && (info != null && info.supportsAmbientMode());
+
+            mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
+            mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
+        }
+    };
+
+    BroadcastReceiver mTaskbarChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mBubblesOptional.ifPresent(bubbles -> bubbles.onTaskbarChanged(intent.getExtras()));
+        }
+    };
+
+    private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+        @Override
+        public void onConfigChanged(Configuration newConfig) {
+            updateResources();
+            updateDisplaySize(); // populates mDisplayMetrics
+
+            if (DEBUG) {
+                Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
+            }
+
+            mViewHierarchyManager.updateRowStates();
+            mScreenPinningRequest.onConfigurationChanged();
+        }
+
+        @Override
+        public void onDensityOrFontScaleChanged() {
+            // TODO: Remove this.
+            if (mBrightnessMirrorController != null) {
+                mBrightnessMirrorController.onDensityOrFontScaleChanged();
+            }
+            // TODO: Bring these out of StatusBar.
+            mUserInfoControllerImpl.onDensityOrFontScaleChanged();
+            mUserSwitcherController.onDensityOrFontScaleChanged();
+            mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
+            mHeadsUpManager.onDensityOrFontScaleChanged();
+        }
+
+        @Override
+        public void onThemeChanged() {
+            if (mStatusBarKeyguardViewManager != null) {
+                mStatusBarKeyguardViewManager.onThemeChanged();
+            }
+            if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
+                ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
+            }
+            mNotificationIconAreaController.onThemeChanged();
+        }
+
+        @Override
+        public void onOverlayChanged() {
+            if (mBrightnessMirrorController != null) {
+                mBrightnessMirrorController.onOverlayChanged();
+            }
+            // We need the new R.id.keyguard_indication_area before recreating
+            // mKeyguardIndicationController
+            mNotificationPanelViewController.onThemeChanged();
+            onThemeChanged();
+        }
+
+        @Override
+        public void onUiModeChanged() {
+            if (mBrightnessMirrorController != null) {
+                mBrightnessMirrorController.onUiModeChanged();
+            }
+        }
+    };
+
+    private StatusBarStateController.StateListener mStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStatePreChange(int oldState, int newState) {
+                    // If we're visible and switched to SHADE_LOCKED (the user dragged
+                    // down on the lockscreen), clear notification LED, vibration,
+                    // ringing.
+                    // Other transitions are covered in handleVisibleToUserChanged().
+                    if (mVisible && (newState == StatusBarState.SHADE_LOCKED
+                            || mStatusBarStateController.goingToFullShade())) {
+                        clearNotificationEffects();
+                    }
+                    if (newState == StatusBarState.KEYGUARD) {
+                        mRemoteInputManager.onPanelCollapsed();
+                        maybeEscalateHeadsUp();
+                    }
+                }
+
+                @Override
+                public void onStateChanged(int newState) {
+                    mState = newState;
+                    updateReportRejectedTouchVisibility();
+                    mDozeServiceHost.updateDozing();
+                    updateTheme();
+                    mNavigationBarController.touchAutoDim(mDisplayId);
+                    Trace.beginSection("StatusBar#updateKeyguardState");
+                    if (mState == StatusBarState.KEYGUARD && mStatusBarView != null) {
+                        mStatusBarView.removePendingHideExpandedRunnables();
+                    }
+                    updateDozingState();
+                    checkBarModes();
+                    updateScrimController();
+                    mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
+                    updateKeyguardState();
+                    Trace.endSection();
+                }
+
+                @Override
+                public void onDozeAmountChanged(float linear, float eased) {
+                    if (mFeatureFlags.useNewLockscreenAnimations()
+                            && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+                        mLightRevealScrim.setRevealAmount(1f - linear);
+                    }
+                }
+
+                @Override
+                public void onDozingChanged(boolean isDozing) {
+                    Trace.beginSection("StatusBar#updateDozing");
+                    mDozing = isDozing;
+
+                    // Collapse the notification panel if open
+                    boolean dozingAnimated = mDozeServiceHost.getDozingRequested()
+                            && mDozeParameters.shouldControlScreenOff();
+                    mNotificationPanelViewController.resetViews(dozingAnimated);
+
+                    updateQsExpansionEnabled();
+                    mKeyguardViewMediator.setDozing(mDozing);
+
+                    mNotificationsController.requestNotificationUpdate("onDozingChanged");
+                    updateDozingState();
+                    mDozeServiceHost.updateDozing();
+                    updateScrimController();
+                    updateReportRejectedTouchVisibility();
+                    Trace.endSection();
+                }
+            };
+
+    private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
+            new BatteryController.BatteryStateChangeCallback() {
+                @Override
+                public void onPowerSaveChanged(boolean isPowerSave) {
+                    mMainExecutor.execute(mCheckBarModes);
+                    if (mDozeServiceHost != null) {
+                        mDozeServiceHost.firePowerSaveChanged(isPowerSave);
+                    }
+                }
+            };
+
+    private final ActivityLaunchAnimator.Callback mKeyguardHandler =
+            new ActivityLaunchAnimator.Callback() {
+                @Override
+                public boolean isOnKeyguard() {
+                    return mKeyguardStateController.isShowing();
+                }
+
+                @Override
+                public void hideKeyguardWithAnimation(IRemoteAnimationRunner runner) {
+                    // We post to the main thread for 2 reasons:
+                    //   1. KeyguardViewMediator is not thread-safe.
+                    //   2. To ensure that ViewMediatorCallback#keyguardDonePending is called before
+                    //      ViewMediatorCallback#readyForKeyguardDone. The wrong order could occur
+                    //      when doing
+                    //      dismissKeyguardThenExecute { hideKeyguardWithAnimation(runner) }.
+                    mMainExecutor.execute(() -> mKeyguardViewMediator.hideWithAnimation(runner));
+                }
+
+                @Override
+                public void setBlursDisabledForAppLaunch(boolean disabled) {
+                    mKeyguardViewMediator.setBlursDisabledForAppLaunch(disabled);
+                }
+
+                @Override
+                public int getBackgroundColor(TaskInfo task) {
+                    if (!mStartingSurfaceOptional.isPresent()) {
+                        Log.w(TAG, "No starting surface, defaulting to SystemBGColor");
+                        return SplashscreenContentDrawer.getSystemBGColor();
+                    }
+
+                    return mStartingSurfaceOptional.get().getBackgroundColor(task);
+                }
+            };
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
index 95f2d0a..6a510c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -256,18 +256,8 @@
     }
 
     @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);
+        mStatusBar.resendMessage(StatusBar.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU);
     }
     /**
      * State is one or more of the DISABLE constants from StatusBarManager.
@@ -330,13 +320,6 @@
             }
         }
 
-        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();
@@ -544,9 +527,7 @@
 
     @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();
+        mStatusBar.resendMessage(new StatusBar.KeyboardShortcutsMessage(deviceId));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
index 1dd22b4..515094b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -19,10 +19,10 @@
 import android.content.Context
 import android.content.res.Resources
 import android.graphics.Rect
+import android.util.LruCache
 import android.util.Pair
 import android.view.DisplayCutout
 import android.view.View.LAYOUT_DIRECTION_RTL
-import android.view.WindowManager
 import android.view.WindowMetrics
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
@@ -37,6 +37,7 @@
 import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
 import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
 import com.android.systemui.util.leak.RotationUtils.Rotation
+import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import java.lang.Math.max
@@ -60,13 +61,14 @@
 class StatusBarContentInsetsProvider @Inject constructor(
     val context: Context,
     val configurationController: ConfigurationController,
-    val windowManager: WindowManager,
     val dumpManager: DumpManager
 ) : CallbackController<StatusBarContentInsetsChangedListener>,
         ConfigurationController.ConfigurationListener,
         Dumpable {
-    // Indexed by @Rotation
-    private val insetsByCorner = arrayOfNulls<Rect>(4)
+
+    // Limit cache size as potentially we may connect large number of displays
+    // (e.g. network displays)
+    private val insetsCache = LruCache<CacheKey, Rect>(MAX_CACHE_SIZE)
     private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>()
 
     init {
@@ -90,12 +92,12 @@
         clearCachedInsets()
     }
 
-    private fun clearCachedInsets() {
-        insetsByCorner[0] = null
-        insetsByCorner[1] = null
-        insetsByCorner[2] = null
-        insetsByCorner[3] = null
+    override fun onMaxBoundsChanged() {
+        notifyInsetsChanged()
+    }
 
+    private fun clearCachedInsets() {
+        insetsCache.evictAll()
         notifyInsetsChanged()
     }
 
@@ -110,10 +112,10 @@
      * dot in the coordinates relative to the given rotation.
      */
     fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect {
-        var insets = insetsByCorner[rotation]
-        val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context)
+        var insets = insetsCache[getCacheKey(rotation = rotation)]
+        val rotatedResources = getResourcesForRotation(rotation, context)
         if (insets == null) {
-            insets = getAndSetInsetsForRotation(rotation, rotatedResources)
+            insets = getStatusBarContentInsetsForRotation(rotation, rotatedResources)
         }
 
         val dotWidth = rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter)
@@ -128,24 +130,16 @@
      * Calculates the necessary left and right locations for the status bar contents invariant of
      * the current device rotation, in the target rotation's coordinates
      */
-    fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Rect {
-        var insets = insetsByCorner[rotation]
-        if (insets == null) {
-            val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context)
-            insets = getAndSetInsetsForRotation(rotation, rotatedResources)
-        }
-
-        return insets
-    }
-
-    private fun getAndSetInsetsForRotation(
-        @Rotation rot: Int,
-        rotatedResources: Resources
+    @JvmOverloads
+    fun getStatusBarContentInsetsForRotation(
+        @Rotation rotation: Int,
+        rotatedResources: Resources = getResourcesForRotation(rotation, context)
     ): Rect {
-        val insets = getCalculatedInsetsForRotation(rot, rotatedResources)
-        insetsByCorner[rot] = insets
-
-        return insets
+        val key = getCacheKey(rotation = rotation)
+        return insetsCache[key] ?: getCalculatedInsetsForRotation(rotation, rotatedResources)
+            .also {
+                insetsCache.put(key, it)
+            }
     }
 
     private fun getCalculatedInsetsForRotation(
@@ -175,17 +169,29 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowManager.maximumWindowMetrics,
+                context.resources.configuration.windowConfiguration.maxBounds,
                 rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height),
                 minLeft,
                 minRight)
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
-        insetsByCorner.forEachIndexed { index, rect ->
-            pw.println("${RotationUtils.toString(index)} -> $rect")
+        insetsCache.snapshot().forEach { (key, rect) ->
+            pw.println("$key -> $rect")
         }
+        pw.println(insetsCache)
     }
+
+    private fun getCacheKey(@Rotation rotation: Int): CacheKey =
+        CacheKey(
+            uniqueDisplayId = context.display.uniqueId,
+            rotation = rotation
+        )
+
+    private data class CacheKey(
+        val uniqueDisplayId: String,
+        @Rotation val rotation: Int
+    )
 }
 
 interface StatusBarContentInsetsChangedListener {
@@ -193,10 +199,9 @@
 }
 
 private const val TAG = "StatusBarInsetsProvider"
+private const val MAX_CACHE_SIZE = 16
 
-private fun getRotationZeroDisplayBounds(wm: WindowMetrics, @Rotation exactRotation: Int): Rect {
-    val bounds = wm.bounds
-
+private fun getRotationZeroDisplayBounds(bounds: Rect, @Rotation exactRotation: Int): Rect {
     if (exactRotation == ROTATION_NONE || exactRotation == ROTATION_UPSIDE_DOWN) {
         return bounds
     }
@@ -242,7 +247,7 @@
     @Rotation currentRotation: Int,
     @Rotation targetRotation: Int,
     displayCutout: DisplayCutout?,
-    windowMetrics: WindowMetrics,
+    maxBounds: Rect,
     statusBarHeight: Int,
     minLeft: Int,
     minRight: Int
@@ -253,16 +258,15 @@
     val right = if (isRtl) paddingStart else paddingEnd
      */
 
-    val rotZeroBounds = getRotationZeroDisplayBounds(windowMetrics, currentRotation)
-    val currentBounds = windowMetrics.bounds
+    val rotZeroBounds = getRotationZeroDisplayBounds(maxBounds, currentRotation)
 
     val sbLeftRight = getStatusBarLeftRight(
             displayCutout,
             statusBarHeight,
             rotZeroBounds.right,
             rotZeroBounds.bottom,
-            currentBounds.width(),
-            currentBounds.height(),
+            maxBounds.width(),
+            maxBounds.height(),
             minLeft,
             minRight,
             targetRotation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 95fd886d..4316ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -73,6 +73,8 @@
 
 import javax.inject.Inject;
 
+import dagger.Lazy;
+
 /**
  * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
  * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
@@ -111,6 +113,7 @@
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
     private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
     private KeyguardMessageAreaController mKeyguardMessageAreaController;
+    private final Lazy<ShadeController> mShadeController;
     private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
         @Override
         public void onFullyShown() {
@@ -243,7 +246,8 @@
             KeyguardBouncer.Factory keyguardBouncerFactory,
             WakefulnessLifecycle wakefulnessLifecycle,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            KeyguardMessageAreaController.Factory keyguardMessageAreaFactory) {
+            KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
+            Lazy<ShadeController> shadeController) {
         mContext = context;
         mViewMediatorCallback = callback;
         mLockPatternUtils = lockPatternUtils;
@@ -260,6 +264,7 @@
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
         mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
+        mShadeController = shadeController;
     }
 
     @Override
@@ -303,8 +308,10 @@
      * Sets a new alt auth interceptor.
      */
     public void setAlternateAuthInterceptor(@NonNull AlternateAuthInterceptor authInterceptor) {
-        mAlternateAuthInterceptor = authInterceptor;
-        resetAlternateAuth(false);
+        if (!Objects.equals(mAlternateAuthInterceptor, authInterceptor)) {
+            mAlternateAuthInterceptor = authInterceptor;
+            resetAlternateAuth(false);
+        }
     }
 
     private void registerListeners() {
@@ -634,6 +641,18 @@
                         });
                 return;
             }
+
+            if (mStatusBar.isLaunchingActivityOverLockscreen()) {
+                mOccluded = true;
+
+                // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post
+                // collapse runnables will be run.
+                mShadeController.get().addPostCollapseAction(() -> {
+                    mNotificationShadeWindowController.setKeyguardOccluded(mOccluded);
+                    reset(true /* hideBouncerWhenShowing */);
+                });
+                return;
+            }
         } else if (!occluded && mOccluded && mShowing) {
             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
                     SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
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 8873fbf..dba3b24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -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/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index cb844d8..832f317 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -47,7 +47,6 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -65,7 +64,6 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -84,28 +82,18 @@
         ConfigurationController.ConfigurationListener,
         NotificationRowBinderImpl.BindRowCallback,
         CommandQueue.Callbacks {
-
-    private final LockscreenGestureLogger mLockscreenGestureLogger =
-            Dependency.get(LockscreenGestureLogger.class);
-
     private static final String TAG = "StatusBarNotificationPresenter";
 
     private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
     private final KeyguardStateController mKeyguardStateController;
-    private final NotificationViewHierarchyManager mViewHierarchyManager =
-            Dependency.get(NotificationViewHierarchyManager.class);
-    private final NotificationLockscreenUserManager mLockscreenUserManager =
-            Dependency.get(NotificationLockscreenUserManager.class);
-    private final SysuiStatusBarStateController mStatusBarStateController =
-            (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
-    private final NotificationEntryManager mEntryManager =
-            Dependency.get(NotificationEntryManager.class);
-    private final NotificationMediaManager mMediaManager =
-            Dependency.get(NotificationMediaManager.class);
-    private final VisualStabilityManager mVisualStabilityManager =
-            Dependency.get(VisualStabilityManager.class);
-    private final NotificationGutsManager mGutsManager =
-            Dependency.get(NotificationGutsManager.class);
+    private final NotificationViewHierarchyManager mViewHierarchyManager;
+    private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private final SysuiStatusBarStateController mStatusBarStateController;
+    private final NotificationEntryManager mEntryManager;
+    private final NotificationMediaManager mMediaManager;
+    private final NotificationGutsManager mGutsManager;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final LockscreenGestureLogger mLockscreenGestureLogger;
 
     private final NotificationPanelViewController mNotificationPanel;
     private final HeadsUpManagerPhone mHeadsUpManager;
@@ -144,8 +132,18 @@
             ShadeController shadeController,
             LockscreenShadeTransitionController shadeTransitionController,
             CommandQueue commandQueue,
+            NotificationViewHierarchyManager notificationViewHierarchyManager,
+            NotificationLockscreenUserManager lockscreenUserManager,
+            SysuiStatusBarStateController sysuiStatusBarStateController,
+            NotificationEntryManager notificationEntryManager,
+            NotificationMediaManager notificationMediaManager,
+            NotificationGutsManager notificationGutsManager,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            LockscreenGestureLogger lockscreenGestureLogger,
             InitController initController,
-            NotificationInterruptStateProvider notificationInterruptStateProvider) {
+            NotificationInterruptStateProvider notificationInterruptStateProvider,
+            NotificationRemoteInputManager remoteInputManager,
+            ConfigurationController configurationController) {
         mKeyguardStateController = keyguardStateController;
         mNotificationPanel = panel;
         mHeadsUpManager = headsUp;
@@ -156,6 +154,14 @@
         mShadeController = shadeController;
         mShadeTransitionController = shadeTransitionController;
         mCommandQueue = commandQueue;
+        mViewHierarchyManager = notificationViewHierarchyManager;
+        mLockscreenUserManager = lockscreenUserManager;
+        mStatusBarStateController = sysuiStatusBarStateController;
+        mEntryManager = notificationEntryManager;
+        mMediaManager = notificationMediaManager;
+        mGutsManager = notificationGutsManager;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mLockscreenGestureLogger = lockscreenGestureLogger;
         mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView());
         mNotificationShadeWindowController = notificationShadeWindowController;
         mAboveShelfObserver.setListener(statusBarWindow.findViewById(
@@ -176,8 +182,6 @@
                 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
             }
         }
-        NotificationRemoteInputManager remoteInputManager =
-                Dependency.get(NotificationRemoteInputManager.class);
         remoteInputManager.setUpWithCallback(
                 Dependency.get(NotificationRemoteInputManager.Callback.class),
                 mNotificationPanel.createRemoteInputDelegate());
@@ -220,14 +224,14 @@
 
             onUserSwitched(mLockscreenUserManager.getCurrentUserId());
         });
-        Dependency.get(ConfigurationController.class).addCallback(this);
+        configurationController.addCallback(this);
     }
 
     @Override
     public void onDensityOrFontScaleChanged() {
         MessagingMessage.dropCache();
         MessagingGroup.dropCache();
-        if (!Dependency.get(KeyguardUpdateMonitor.class).isSwitchingUser()) {
+        if (!mKeyguardUpdateMonitor.isSwitchingUser()) {
             updateNotificationsOnDensityOrFontScaleChanged();
         } else {
             mReinflateNotificationsOnUserSwitched = true;
@@ -236,7 +240,7 @@
 
     @Override
     public void onUiModeChanged() {
-        if (!Dependency.get(KeyguardUpdateMonitor.class).isSwitchingUser()) {
+        if (!mKeyguardUpdateMonitor.isSwitchingUser()) {
             updateNotificationOnUiModeChanged();
         } else {
             mDispatchUiModeChangeOnUserSwitched = true;
@@ -308,17 +312,11 @@
     private void onNotificationRemoved(String key, StatusBarNotification old, int reason) {
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
 
-        if (old != null) {
-            if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
-                    && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
-                if (mStatusBarStateController.getState() == StatusBarState.SHADE
-                        && reason != NotificationListenerService.REASON_CLICK) {
-                    mCommandQueue.animateCollapsePanels();
-                } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
+        if (old != null && CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
+                && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()
+                && mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
                         && !isCollapsing()) {
-                    mStatusBarStateController.setState(StatusBarState.KEYGUARD);
-                }
-            }
+                mStatusBarStateController.setState(StatusBarState.KEYGUARD);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 3d3b58a..aec27d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -43,7 +43,6 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 
 import javax.inject.Inject;
 
@@ -58,14 +57,13 @@
     private final Context mContext;
     private final WindowManager mWindowManager;
     private final IWindowManager mIWindowManager;
-    private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     private final StatusBarContentInsetsProvider mContentInsetsProvider;
     private final Resources mResources;
     private int mBarHeight = -1;
     private final State mCurrentState = new State();
 
-    private ViewGroup mStatusBarView;
-    private ViewGroup mLaunchAnimationContainer;
+    private final ViewGroup mStatusBarView;
+    private final ViewGroup mLaunchAnimationContainer;
     private WindowManager.LayoutParams mLp;
     private final WindowManager.LayoutParams mLpChanged;
 
@@ -74,15 +72,14 @@
             Context context,
             WindowManager windowManager,
             IWindowManager iWindowManager,
-            SuperStatusBarViewFactory superStatusBarViewFactory,
+            StatusBarWindowView statusBarWindowView,
             StatusBarContentInsetsProvider contentInsetsProvider,
             @Main Resources resources) {
         mContext = context;
         mWindowManager = windowManager;
         mIWindowManager = iWindowManager;
         mContentInsetsProvider = contentInsetsProvider;
-        mSuperStatusBarViewFactory = superStatusBarViewFactory;
-        mStatusBarView = mSuperStatusBarViewFactory.getStatusBarWindowView();
+        mStatusBarView = statusBarWindowView;
         mLaunchAnimationContainer = mStatusBarView.findViewById(
                 R.id.status_bar_launch_animation_container);
         mLpChanged = new WindowManager.LayoutParams();
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..f8120a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -5,20 +5,23 @@
 import android.animation.ValueAnimator
 import android.content.Context
 import android.content.res.Configuration
+import android.database.ContentObserver
 import android.os.Handler
+import android.provider.Settings
+import com.android.systemui.statusbar.StatusBarState
 import android.view.View
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.statusbar.LightRevealScrim
-import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.StatusBarStateControllerImpl
 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.settings.GlobalSettings
 import javax.inject.Inject
 
 /**
@@ -46,13 +49,16 @@
     private val statusBarStateControllerImpl: StatusBarStateControllerImpl,
     private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>,
     private val keyguardStateController: KeyguardStateController,
-    private val dozeParameters: dagger.Lazy<DozeParameters>
+    private val dozeParameters: dagger.Lazy<DozeParameters>,
+    private val globalSettings: GlobalSettings
 ) : WakefulnessLifecycle.Observer {
     private val handler = Handler()
 
     private lateinit var statusBar: StatusBar
     private lateinit var lightRevealScrim: LightRevealScrim
 
+    private var animatorDurationScale = 1f
+    private var shouldAnimateInKeyguard = false
     private var lightRevealAnimationPlaying = false
     private var aodUiAnimationPlaying = false
 
@@ -79,6 +85,12 @@
         })
     }
 
+    val animatorDurationScaleObserver = object : ContentObserver(null) {
+        override fun onChange(selfChange: Boolean) {
+            updateAnimatorDurationScale()
+        }
+    }
+
     fun initialize(
         statusBar: StatusBar,
         lightRevealScrim: LightRevealScrim
@@ -86,14 +98,25 @@
         this.lightRevealScrim = lightRevealScrim
         this.statusBar = statusBar
 
+        updateAnimatorDurationScale()
+        globalSettings.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+                /* notify for descendants */ false,
+                animatorDurationScaleObserver)
         wakefulnessLifecycle.addObserver(this)
     }
 
+    fun updateAnimatorDurationScale() {
+        animatorDurationScale =
+                globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f)
+    }
+
     /**
      * Animates in the provided keyguard view, ending in the same position that it will be in on
      * AOD.
      */
     fun animateInKeyguard(keyguardView: View, after: Runnable) {
+        shouldAnimateInKeyguard = false
         keyguardView.alpha = 0f
         keyguardView.visibility = View.VISIBLE
 
@@ -138,6 +161,7 @@
         // Waking up, so reset this flag.
         decidedToAnimateGoingToSleep = null
 
+        shouldAnimateInKeyguard = false
         lightRevealAnimator.cancel()
         handler.removeCallbacksAndMessages(null)
     }
@@ -146,32 +170,35 @@
         // Set this to false in onFinishedWakingUp rather than onStartedWakingUp so that other
         // observers (such as StatusBar) can ask us whether we were playing the screen off animation
         // and reset accordingly.
-        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() {
         if (dozeParameters.get().shouldControlUnlockedScreenOff()) {
             decidedToAnimateGoingToSleep = true
 
+            shouldAnimateInKeyguard = true
             lightRevealAnimationPlaying = true
             lightRevealAnimator.start()
-
             handler.postDelayed({
                 aodUiAnimationPlaying = true
 
                 // Show AOD. That'll cause the KeyguardVisibilityHelper to call #animateInKeyguard.
                 statusBar.notificationPanelViewController.showAodUi()
-            }, ANIMATE_IN_KEYGUARD_DELAY)
+            }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong())
         } else {
             decidedToAnimateGoingToSleep = false
         }
@@ -224,6 +251,10 @@
         return lightRevealAnimationPlaying || aodUiAnimationPlaying
     }
 
+    fun shouldAnimateInKeyguard(): Boolean {
+        return shouldAnimateInKeyguard
+    }
+
     /**
      * Whether the light reveal animation is playing. The second part of the screen off animation,
      * where AOD animates in, might still be playing if this returns false.
@@ -231,4 +262,4 @@
     fun isScreenOffLightRevealAnimationPlaying(): Boolean {
         return lightRevealAnimationPlaying
     }
-}
\ No newline at end of file
+}
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 d408c0c..418f588 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
@@ -20,6 +20,8 @@
 
 import com.android.keyguard.LockIconViewController;
 import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.statusbar.NotificationShelfController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
@@ -34,7 +36,6 @@
 
 import javax.inject.Scope;
 
-import dagger.BindsInstance;
 import dagger.Subcomponent;
 
 /**
@@ -46,11 +47,9 @@
     /**
      * Builder for {@link StatusBarComponent}.
      */
-    @Subcomponent.Builder
-    interface Builder {
-        @BindsInstance Builder statusBarWindowView(
-                NotificationShadeWindowView notificationShadeWindowView);
-        StatusBarComponent build();
+    @Subcomponent.Factory
+    interface Factory {
+        StatusBarComponent create();
     }
 
     /**
@@ -62,6 +61,21 @@
     @interface StatusBarScope {}
 
     /**
+     * Creates a {@link NotificationShadeWindowView}/
+     * @return
+     */
+    @StatusBarScope
+    NotificationShadeWindowView getNotificationShadeWindowView();
+
+    /** */
+    @StatusBarScope
+    NotificationShelfController getNotificationShelfController();
+
+    /** */
+    @StatusBarScope
+    NotificationStackScrollLayoutController getNotificationStackScrollLayoutController();
+
+    /**
      * Creates a NotificationShadeWindowViewController.
      */
     @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 7ad0e7f..a7b57b9 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
@@ -33,6 +33,7 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.flags.FeatureFlags;
@@ -55,11 +56,12 @@
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -77,6 +79,7 @@
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LightsOutNotifController;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
@@ -88,6 +91,7 @@
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -98,10 +102,13 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.unfold.config.UnfoldTransitionConfig;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.concurrency.MessageRouter;
 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;
@@ -110,7 +117,6 @@
 import java.util.concurrent.Executor;
 
 import javax.inject.Named;
-import javax.inject.Provider;
 
 import dagger.Lazy;
 import dagger.Module;
@@ -142,6 +148,7 @@
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
+            NotificationEntryManager notificationEntryManager,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -171,6 +178,7 @@
             DozeParameters dozeParameters,
             ScrimController scrimController,
             Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            LockscreenGestureLogger lockscreenGestureLogger,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
             PowerManager powerManager,
@@ -178,14 +186,14 @@
             DozeScrimController dozeScrimController,
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
-            Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
+            StatusBarComponent.Factory statusBarComponentFactory,
             PluginManager pluginManager,
             Optional<LegacySplitScreen> splitScreenOptional,
             LightsOutNotifController lightsOutNotifController,
             StatusBarNotificationActivityStarter.Builder
                     statusBarNotificationActivityStarterBuilder,
             ShadeController shadeController,
-            SuperStatusBarViewFactory superStatusBarViewFactory,
+            StatusBarWindowView statusBarWindowView,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             ViewMediatorCallback viewMediatorCallback,
             InitController initController,
@@ -194,6 +202,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            OperatorNameViewController.Factory operatorNameViewControllerFactory,
             PhoneStatusBarPolicy phoneStatusBarPolicy,
             KeyguardIndicationController keyguardIndicationController,
             DemoModeController demoModeController,
@@ -210,9 +219,13 @@
             LockscreenShadeTransitionController transitionController,
             FeatureFlags featureFlags,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+            @Main Handler mainHandler,
+            @Main DelayableExecutor delayableExecutor,
+            @Main MessageRouter messageRouter,
             WallpaperManager wallpaperManager,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Optional<StartingSurface> startingSurfaceOptional) {
+            Optional<StartingSurface> startingSurfaceOptional,
+            TunerService tunerService) {
         return new StatusBar(
                 context,
                 notificationsController,
@@ -229,6 +242,7 @@
                 falsingManager,
                 falsingCollector,
                 broadcastDispatcher,
+                notificationEntryManager,
                 notificationGutsManager,
                 notificationLogger,
                 notificationInterruptStateProvider,
@@ -258,6 +272,7 @@
                 dozeParameters,
                 scrimController,
                 lockscreenWallpaperLazy,
+                lockscreenGestureLogger,
                 biometricUnlockControllerLazy,
                 dozeServiceHost,
                 powerManager,
@@ -265,13 +280,13 @@
                 dozeScrimController,
                 volumeComponent,
                 commandQueue,
-                statusBarComponentBuilder,
+                statusBarComponentFactory,
                 pluginManager,
                 splitScreenOptional,
                 lightsOutNotifController,
                 statusBarNotificationActivityStarterBuilder,
                 shadeController,
-                superStatusBarViewFactory,
+                statusBarWindowView,
                 statusBarKeyguardViewManager,
                 viewMediatorCallback,
                 initController,
@@ -280,6 +295,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                operatorNameViewControllerFactory,
                 phoneStatusBarPolicy,
                 keyguardIndicationController,
                 demoModeController,
@@ -296,8 +312,12 @@
                 transitionController,
                 featureFlags,
                 keyguardUnlockAnimationController,
+                mainHandler,
+                delayableExecutor,
+                messageRouter,
                 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 0e83eda..ecf3b86 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
@@ -17,15 +17,23 @@
 package com.android.systemui.statusbar.phone.dagger;
 
 import android.annotation.Nullable;
+import android.content.Context;
+import android.view.LayoutInflater;
 import android.view.View;
 
 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.NotificationShelf;
+import com.android.systemui.statusbar.NotificationShelfController;
+import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.TapAgainView;
+import com.android.systemui.util.InjectionInflationController;
 
 import javax.inject.Named;
 
@@ -40,6 +48,63 @@
     /** */
     @Provides
     @StatusBarComponent.StatusBarScope
+    public static NotificationShadeWindowView providesNotificationShadeWindowView(
+            InjectionInflationController injectionInflationController,
+            Context context) {
+        NotificationShadeWindowView notificationShadeWindowView = (NotificationShadeWindowView)
+                injectionInflationController.injectable(
+                        LayoutInflater.from(context)).inflate(R.layout.super_notification_shade,
+                        /* root= */ null);
+        if (notificationShadeWindowView == null) {
+            throw new IllegalStateException(
+                    "R.layout.super_notification_shade could not be properly inflated");
+        }
+
+        return notificationShadeWindowView;
+    }
+
+    /** */
+    @Provides
+    @StatusBarComponent.StatusBarScope
+    public static NotificationStackScrollLayout providesNotificationStackScrollLayout(
+            NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
+        return notificationStackScrollLayoutController.getView();
+    }
+
+    /** */
+    @Provides
+    @StatusBarComponent.StatusBarScope
+    public static NotificationShelf providesNotificationShelf(LayoutInflater layoutInflater,
+            NotificationStackScrollLayout notificationStackScrollLayout) {
+        NotificationShelf view = (NotificationShelf) layoutInflater.inflate(
+                R.layout.status_bar_notification_shelf, notificationStackScrollLayout, false);
+
+        if (view == null) {
+            throw new IllegalStateException(
+                    "R.layout.status_bar_notification_shelf could not be properly inflated");
+        }
+        return view;
+    }
+
+    /** */
+    @Provides
+    @StatusBarComponent.StatusBarScope
+    public static NotificationShelfController providesStatusBarWindowView(
+            NotificationShelfComponent.Builder notificationShelfComponentBuilder,
+            NotificationShelf notificationShelf) {
+        NotificationShelfComponent component = notificationShelfComponentBuilder
+                .notificationShelf(notificationShelf)
+                .build();
+        NotificationShelfController notificationShelfController =
+                component.getNotificationShelfController();
+        notificationShelfController.init();
+
+        return notificationShelfController;
+    }
+
+    /** */
+    @Provides
+    @StatusBarComponent.StatusBarScope
     public static NotificationPanelView getNotificationPanelView(
             NotificationShadeWindowView notificationShadeWindowView) {
         return notificationShadeWindowView.getNotificationPanelView();
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 1db6ce4..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
@@ -216,6 +216,10 @@
         isCallAppVisible = isProcessVisibleToUser(
                 iActivityManager.getUidProcessState(currentCallNotificationInfo.uid, null))
 
+        if (uidObserver != null) {
+            iActivityManager.unregisterUidObserver(uidObserver)
+        }
+
         uidObserver = object : IUidObserver.Stub() {
             override fun onUidStateChanged(
                 uid: Int,
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 d80fa12..f54bb68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -68,6 +68,7 @@
 
     private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>();
     private final UserManager mUserManager;
+    private final UserTracker mUserTracker;
     private final Executor mMainExecutor;
 
     private @Nullable WifiPickerTracker mWifiPickerTracker;
@@ -84,6 +85,7 @@
             WifiPickerTrackerFactory wifiPickerTrackerFactory
     ) {
         mUserManager = userManager;
+        mUserTracker = userTracker;
         mCurrentUser = userTracker.getUserId();
         mMainExecutor = mainExecutor;
         mWifiPickerTrackerFactory = wifiPickerTrackerFactory;
@@ -120,7 +122,7 @@
 
     public boolean canConfigMobileData() {
         return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
-                UserHandle.of(mCurrentUser));
+                UserHandle.of(mCurrentUser)) && mUserTracker.getUserInfo().isAdmin();
     }
 
     public void onUserSwitched(int newUserId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 3a05ec7..e679c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -37,6 +37,7 @@
         default void onConfigChanged(Configuration newConfig) {}
         default void onDensityOrFontScaleChanged() {}
         default void onSmallestScreenWidthChanged() {}
+        default void onMaxBoundsChanged() {}
         default void onOverlayChanged() {}
         default void onUiModeChanged() {}
         default void onThemeChanged() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 5e70d0d..b6c683f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -33,11 +33,14 @@
 import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
 import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.R;
+import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.qs.user.UserSwitchDialogController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -75,6 +78,8 @@
     private final ConfigurationController mConfigurationController;
     private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
     private final KeyguardUserDetailAdapter mUserDetailAdapter;
+    private final FeatureFlags mFeatureFlags;
+    private final UserSwitchDialogController mUserSwitchDialogController;
     private NotificationPanelViewController mNotificationPanelViewController;
     UserSwitcherController.UserRecord mCurrentUser;
 
@@ -116,13 +121,16 @@
             @Main Resources resources,
             ScreenLifecycle screenLifecycle,
             UserSwitcherController userSwitcherController,
+            CommunalStateController communalStateController,
             KeyguardStateController keyguardStateController,
             FalsingManager falsingManager,
             ConfigurationController configurationController,
             SysuiStatusBarStateController statusBarStateController,
             DozeParameters dozeParameters,
             Provider<UserDetailView.Adapter> userDetailViewAdapterProvider,
-            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
+            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+            FeatureFlags featureFlags,
+            UserSwitchDialogController userSwitchDialogController) {
         super(view);
         if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController");
         mContext = context;
@@ -133,10 +141,13 @@
         mFalsingManager = falsingManager;
         mConfigurationController = configurationController;
         mStatusBarStateController = statusBarStateController;
-        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
+        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
                 keyguardStateController, dozeParameters,
-                unlockedScreenOffAnimationController,  /* animateYPos= */ false);
+                unlockedScreenOffAnimationController,  /* animateYPos= */ false,
+                /* visibleOnCommunal= */ false);
         mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider);
+        mFeatureFlags = featureFlags;
+        mUserSwitchDialogController = userSwitchDialogController;
     }
 
     @Override
@@ -160,7 +171,11 @@
             }
 
             // Tapping anywhere in the view will open QS user panel
-            openQsUserPanel();
+            if (mFeatureFlags.useNewUserSwitcher()) {
+                mUserSwitchDialogController.showDialog(mView);
+            } else {
+                openQsUserPanel();
+            }
         });
 
         mView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 742b1ab..7bf1601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -251,5 +251,11 @@
          * {@link KeyguardStateController#isFaceAuthEnabled()}.
          */
         default void onFaceAuthEnabledChanged() {}
+
+        /**
+         * Triggered when the notification panel is starting or has finished
+         * fading away on transition to an app.
+         */
+        default void onLaunchTransitionFadingAwayChanged() {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 64750bd..f787ecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -343,6 +343,7 @@
     @Override
     public void setLaunchTransitionFadingAway(boolean fadingAway) {
         mLaunchTransitionFadingAway = fadingAway;
+        new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 43b2061..c4b5961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -42,6 +42,7 @@
 import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -157,6 +158,7 @@
             LayoutInflater layoutInflater,
             ScreenLifecycle screenLifecycle,
             UserSwitcherController userSwitcherController,
+            CommunalStateController communalStateController,
             KeyguardStateController keyguardStateController,
             SysuiStatusBarStateController statusBarStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -172,9 +174,10 @@
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mAdapter = new KeyguardUserAdapter(mContext, resources, layoutInflater,
                 mUserSwitcherController, this);
-        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
+        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
                 keyguardStateController, dozeParameters,
-                unlockedScreenOffAnimationController, /* animateYPos= */ false);
+                unlockedScreenOffAnimationController, /* animateYPos= */ false,
+                /* visibleOnCommunal= */ false);
         mBackground = new KeyguardUserSwitcherScrim(context);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 20b66f0..cd8894c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -103,7 +103,7 @@
             }
         }
 
-        if (animate) {
+        if (animate && userItemViews.length > 1) {
             // AnimationUtils will immediately hide/show the first item in the array. Since the
             // first view is the current user, we want to manage its visibility separately.
             // Set first item to null so AnimationUtils ignores it.
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 d6ac6d1..3bfc2a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -71,6 +71,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
 import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
@@ -129,6 +130,7 @@
     private Config mConfig;
     private final CarrierConfigTracker mCarrierConfigTracker;
     private final FeatureFlags mFeatureFlags;
+    private final DumpManager mDumpManager;
 
     private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -225,7 +227,8 @@
             CarrierConfigTracker carrierConfigTracker,
             @Main Handler handler,
             InternetDialogFactory internetDialogFactory,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            DumpManager dumpManager) {
         this(context, connectivityManager,
                 telephonyManager,
                 telephonyListenerManager,
@@ -243,7 +246,8 @@
                 broadcastDispatcher,
                 demoModeController,
                 carrierConfigTracker,
-                featureFlags);
+                featureFlags,
+                dumpManager);
         mReceiverHandler.post(mRegisterListeners);
         mMainHandler = handler;
         mInternetDialogFactory = internetDialogFactory;
@@ -265,7 +269,8 @@
             BroadcastDispatcher broadcastDispatcher,
             DemoModeController demoModeController,
             CarrierConfigTracker carrierConfigTracker,
-            FeatureFlags featureFlags
+            FeatureFlags featureFlags,
+            DumpManager dumpManager
     ) {
         mContext = context;
         mTelephonyListenerManager = telephonyListenerManager;
@@ -284,6 +289,7 @@
         mDemoModeController = demoModeController;
         mCarrierConfigTracker = carrierConfigTracker;
         mFeatureFlags = featureFlags;
+        mDumpManager = dumpManager;
 
         // telephony
         mPhone = telephonyManager;
@@ -434,6 +440,8 @@
         mDemoModeController.addCallback(this);
         mProviderModelBehavior = mFeatureFlags.isCombinedStatusBarSignalIconsEnabled();
         mProviderModelSetting = mFeatureFlags.isProviderModelSettingEnabled();
+
+        mDumpManager.registerDumpable(TAG, this);
     }
 
     private final Runnable mClearForceValidated = () -> {
@@ -793,8 +801,8 @@
                 mReceiverHandler.post(this::handleConfigurationChanged);
                 break;
             case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
-                boolean canConfigMobileData = mAccessPoints.canConfigMobileData();
-                mMainHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
+                mMainHandler.post(() -> mInternetDialogFactory.create(true,
+                        mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi()));
                 break;
             default:
                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 7f3152c..1398c52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -76,7 +76,6 @@
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
-import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -205,7 +204,7 @@
         final int stroke = colorized ? mContext.getResources().getDimensionPixelSize(
                 R.dimen.remote_input_view_text_stroke) : 0;
         if (colorized) {
-            final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
+            final boolean dark = Notification.Builder.isColorDark(backgroundColor);
             final int foregroundColor = dark ? Color.WHITE : Color.BLACK;
             final int inverseColor = dark ? Color.BLACK : Color.WHITE;
             editBgColor = backgroundColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index b563d86..21d0338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -311,7 +311,7 @@
                             setBounds(0, 0, newIconSize, newIconSize)
                         }
                 // Add the action icon to the Smart Action button.
-                setCompoundDrawables(iconDrawable, null, null, null)
+                setCompoundDrawablesRelative(iconDrawable, null, null, null)
 
                 val onClickListener = View.OnClickListener {
                     onSmartActionClick(entry, smartActions, actionIndex, action)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 41b1dd1..a3e27be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -503,15 +503,15 @@
     }
 
     /**
-     * Returns the combined width of the left drawable (the action icon) and the padding between the
-     * drawable and the button text.
+     * Returns the combined width of the start drawable (the action icon) and the padding between
+     * the drawable and the button text.
      */
-    private int getLeftCompoundDrawableWidthWithPadding(Button button) {
-        Drawable[] drawables = button.getCompoundDrawables();
-        Drawable leftDrawable = drawables[0];
-        if (leftDrawable == null) return 0;
+    private int getStartCompoundDrawableWidthWithPadding(Button button) {
+        Drawable[] drawables = button.getCompoundDrawablesRelative();
+        Drawable startDrawable = drawables[0];
+        if (startDrawable == null) return 0;
 
-        return leftDrawable.getBounds().width() + button.getCompoundDrawablePadding();
+        return startDrawable.getBounds().width() + button.getCompoundDrawablePadding();
     }
 
     private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
@@ -520,8 +520,8 @@
         // Re-measure the squeezed smart reply button.
         clearLayoutLineCount(button);
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                button.getPaddingLeft() + button.getPaddingRight() + textWidth
-                      + getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
+                button.getPaddingStart() + button.getPaddingEnd() + textWidth
+                      + getStartCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
         button.measure(widthMeasureSpec, heightMeasureSpec);
 
         final int newWidth = button.getMeasuredWidth();
@@ -628,7 +628,7 @@
         mCurrentBackgroundColor = backgroundColor;
         mCurrentColorized = colorized;
 
-        final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
+        final boolean dark = Notification.Builder.isColorDark(backgroundColor);
 
         mCurrentTextColor = ContrastColorUtil.ensureTextContrast(
                 dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
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/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index c3b4fbe..fe0b970 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -132,14 +132,18 @@
     /* Target package for each overlay category. */
     private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
     private final OverlayManager mOverlayManager;
-    private final Executor mExecutor;
+    private final Executor mBgExecutor;
+    private final Executor mMainExecutor;
     private final String mLauncherPackage;
     private final String mThemePickerPackage;
 
-    public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor,
+    public ThemeOverlayApplier(OverlayManager overlayManager,
+            Executor bgExecutor,
+            Executor mainExecutor,
             String launcherPackage, String themePickerPackage, DumpManager dumpManager) {
         mOverlayManager = overlayManager;
-        mExecutor = executor;
+        mBgExecutor = bgExecutor;
+        mMainExecutor = mainExecutor;
         mLauncherPackage = launcherPackage;
         mThemePickerPackage = themePickerPackage;
         mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
@@ -170,12 +174,13 @@
      * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that
      * affect sysui will also be applied to the system user.
      */
-    void applyCurrentUserOverlays(
+    public void applyCurrentUserOverlays(
             Map<String, OverlayIdentifier> categoryToPackage,
             FabricatedOverlay[] pendingCreation,
             int currentUser,
-            Set<UserHandle> managedProfiles) {
-        mExecutor.execute(() -> {
+            Set<UserHandle> managedProfiles,
+            Runnable onOverlaysApplied) {
+        mBgExecutor.execute(() -> {
 
             // Disable all overlays that have not been specified in the user setting.
             final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
@@ -221,6 +226,7 @@
 
             try {
                 mOverlayManager.commit(transaction.build());
+                mMainExecutor.execute(onOverlaysApplied);
             } catch (SecurityException | IllegalStateException e) {
                 Log.e(TAG, "setEnabled failed", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index cfd82f5..a5871f0 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -526,17 +526,21 @@
                     .map(key -> key + " -> " + categoryToPackage.get(key)).collect(
                             Collectors.joining(", ")));
         }
+        Runnable overlaysAppliedRunnable = () -> onOverlaysApplied();
         if (mNeedsOverlayCreation) {
             mNeedsOverlayCreation = false;
             mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
                     mSecondaryOverlay, mNeutralOverlay
-            }, currentUser, managedProfiles);
+            }, currentUser, managedProfiles, overlaysAppliedRunnable);
         } else {
             mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
-                    managedProfiles);
+                    managedProfiles, overlaysAppliedRunnable);
         }
     }
 
+    protected void onOverlaysApplied() {
+    }
+
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("mSystemColors=" + mCurrentColors);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
index 0a29e04..20857ea 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
@@ -106,8 +106,8 @@
                 PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
         apps.forEach(app -> {
             if (!plugins.containsKey(app.packageName)) return;
-            if (ArrayUtils.contains(manager.getWhitelistedPlugins(), app.packageName)) {
-                // Don't manage whitelisted plugins, they are part of the OS.
+            if (ArrayUtils.contains(manager.getPrivilegedPlugins(), app.packageName)) {
+                // Don't manage privileged plugins, they are part of the OS.
                 return;
             }
             SwitchPreference pref = new PluginPreference(prefContext, app, mPluginEnabler);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 3525100..8912448 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -70,6 +70,7 @@
 import com.android.systemui.statusbar.policy.SensorPrivacyController;
 import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
 import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
+import com.android.systemui.volume.dagger.VolumeModule;
 
 import javax.inject.Named;
 
@@ -83,7 +84,8 @@
  */
 @Module(includes = {
             PowerModule.class,
-            QSModule.class
+            QSModule.class,
+            VolumeModule.class,
         },
         subcomponents = {
         })
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 8e7c49a..3c3cc64 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -23,8 +23,7 @@
 import android.view.WindowManager
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.unfold.UnfoldTransitionProgressProvider
-import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.LinearLightRevealEffect
 import java.util.concurrent.Executor
@@ -59,6 +58,10 @@
         }
 
         override fun onTransitionStarted() {
+            // When unfolding the view is added earlier, add view for folding case
+            if (scrimView == null) {
+                addOverlayView()
+            }
         }
     }
 
@@ -93,7 +96,7 @@
         val newScrimView = LightRevealScrim(context, null)
             .apply {
                 revealEffect = LinearLightRevealEffect(isVerticalFold)
-                revealAmountListener = Consumer {}
+                isScrimOpaqueChangedListener = Consumer {}
                 revealAmount = 0f
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 98b4209e..bfa50bc 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.TextView;
@@ -63,6 +64,8 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        getWindow().addPrivateFlags(
+                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         Intent intent = getIntent();
         mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
         mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 32bbe1c..0dd5788 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -110,16 +110,6 @@
     }
 
     /**
-     * Destroys this controller so that it never receives view attach and detach events again.
-     * Does nothing if the view is null.
-     */
-    public void destroy() {
-        if (mView != null) {
-            mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
-        }
-    }
-
-    /**
      * Called when the view is attached and a call to {@link #init()} has been made in either order.
      */
     protected abstract void onViewAttached();
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
index 1c50496..107fe87 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -22,8 +22,10 @@
 
 import com.android.systemui.dagger.qualifiers.Main;
 
+import java.util.Optional;
 import java.util.concurrent.Executor;
 
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import dagger.Binds;
@@ -35,6 +37,7 @@
  */
 @Module
 public abstract class GlobalConcurrencyModule {
+    public static final String PRE_HANDLER = "pre_handler";
 
     /**
      * Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
@@ -64,13 +67,32 @@
      * Provide a Main-Thread Executor.
      */
     @Provides
+    @Singleton
     @Main
     public static Executor provideMainExecutor(Context context) {
         return context.getMainExecutor();
     }
 
+    /**
+     * Provide a Main-Thread DelayableExecutor.
+     */
+    @Provides
+    @Singleton
+    @Main
+    public static DelayableExecutor provideMainDelayableExecutor(@Main Looper looper) {
+        return new ExecutorImpl(looper);
+    }
+
+
     /** */
     @Binds
     @Singleton
     public abstract Execution provideExecution(ExecutionImpl execution);
+
+    /** */
+    @Provides
+    @Named(PRE_HANDLER)
+    public static Optional<Thread.UncaughtExceptionHandler> providesUncaughtExceptionHandler() {
+        return Optional.ofNullable(Thread.getUncaughtExceptionPreHandler());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index e9e794e..e8a9bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -120,16 +120,6 @@
     }
 
     /**
-     * Provide a Main-Thread Executor.
-     */
-    @Provides
-    @SysUISingleton
-    @Main
-    public static DelayableExecutor provideMainDelayableExecutor(@Main Looper looper) {
-        return new ExecutorImpl(looper);
-    }
-
-    /**
      * Provide a Background-Thread Executor by default.
      */
     @Provides
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 b38fc77..bd11039 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -87,15 +87,23 @@
                     && (mLastPrimaryEvent == null
                     || !mLastPrimaryEvent.getBelow()
                     || !event.getBelow())) {
-                mSecondaryThresholdSensor.pause();
+                chooseSensor();
                 if (mLastPrimaryEvent == null || !mLastPrimaryEvent.getBelow()) {
                     // Only check the secondary as long as the primary thinks we're near.
-                    mCancelSecondaryRunnable = null;
+                    if (mCancelSecondaryRunnable != null) {
+                        mCancelSecondaryRunnable.run();
+                        mCancelSecondaryRunnable = null;
+                    }
                     return;
                 } else {
                     // Check this sensor again in a moment.
-                    mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(
-                            mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS);
+                    mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(() -> {
+                        // This is safe because we know that mSecondaryThresholdSensor
+                        // is loaded, otherwise we wouldn't be here.
+                        mPrimaryThresholdSensor.pause();
+                        mSecondaryThresholdSensor.resume();
+                    },
+                        SECONDARY_PING_INTERVAL_MS);
                 }
             }
             logDebug("Secondary sensor event: " + event.getBelow() + ".");
@@ -159,12 +167,8 @@
      * of what is reported by the primary sensor.
      */
     public void setSecondarySafe(boolean safe) {
-        mSecondarySafe = safe;
-        if (!mSecondarySafe) {
-            mSecondaryThresholdSensor.pause();
-        } else {
-            mSecondaryThresholdSensor.resume();
-        }
+        mSecondarySafe = mSecondaryThresholdSensor.isLoaded() && safe;
+        chooseSensor();
     }
 
     /**
@@ -209,16 +213,30 @@
             return;
         }
         if (!mInitializedListeners) {
+            mPrimaryThresholdSensor.pause();
+            mSecondaryThresholdSensor.pause();
             mPrimaryThresholdSensor.register(mPrimaryEventListener);
-            if (!mSecondarySafe) {
-                mSecondaryThresholdSensor.pause();
-            }
             mSecondaryThresholdSensor.register(mSecondaryEventListener);
             mInitializedListeners = true;
         }
         logDebug("Registering sensor listener");
-        mPrimaryThresholdSensor.resume();
+
         mRegistered = true;
+        chooseSensor();
+    }
+
+    private void chooseSensor() {
+        mExecution.assertIsMainThread();
+        if (!mRegistered || mPaused || mListeners.isEmpty()) {
+            return;
+        }
+        if (mSecondarySafe) {
+            mSecondaryThresholdSensor.resume();
+            mPrimaryThresholdSensor.pause();
+        } else {
+            mPrimaryThresholdSensor.resume();
+            mSecondaryThresholdSensor.pause();
+        }
     }
 
     /**
@@ -290,15 +308,18 @@
             return;
         }
 
-        if (!mSecondaryThresholdSensor.isLoaded()) {
+
+        if (!mSecondaryThresholdSensor.isLoaded()) {  // No secondary
             logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
             onSensorEvent(event);
-        } else if (event.getBelow()) {
+        } 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);
         }
     }
 
@@ -309,7 +330,7 @@
         }
 
         if (!mSecondarySafe && !event.getBelow()) {
-            mSecondaryThresholdSensor.pause();
+            chooseSensor();
         }
 
         mLastEvent = event;
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/BuildInfo.java b/packages/SystemUI/src/com/android/systemui/util/wrapper/BuildInfo.java
index 5e68a15..d91a140 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wrapper/BuildInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/BuildInfo.java
@@ -32,6 +32,8 @@
 
     /** @see Build#IS_DEBUGGABLE */
     public boolean isDebuggable() {
-        return Build.IS_DEBUGGABLE;
+        // Build.IS_DEBUGGABLE is inlined by the gradle build, causing this to incorrectly
+        // return false when using sysui-studio.
+        return Build.isDebuggable();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 56f1c09..c083c14 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -20,13 +20,11 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
-import android.media.AudioManager;
 import android.media.VolumePolicy;
 import android.os.Bundle;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.settingslib.applications.InterestingConfigChanges;
-import com.android.systemui.Dependency;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
@@ -67,6 +65,7 @@
             ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
             | ActivityInfo.CONFIG_ASSETS_PATHS | ActivityInfo.CONFIG_UI_MODE);
     private final KeyguardViewMediator mKeyguardViewMediator;
+    private final ActivityStarter mActivityStarter;
     private VolumeDialog mDialog;
     private VolumePolicy mVolumePolicy = new VolumePolicy(
             DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT,  // volumeDownToEnterSilent
@@ -79,18 +78,23 @@
     public VolumeDialogComponent(
             Context context,
             KeyguardViewMediator keyguardViewMediator,
+            ActivityStarter activityStarter,
             VolumeDialogControllerImpl volumeDialogController,
-            DemoModeController demoModeController) {
+            DemoModeController demoModeController,
+            PluginDependencyProvider pluginDependencyProvider,
+            ExtensionController extensionController,
+            TunerService tunerService,
+            VolumeDialog volumeDialog) {
         mContext = context;
         mKeyguardViewMediator = keyguardViewMediator;
+        mActivityStarter = activityStarter;
         mController = volumeDialogController;
         mController.setUserActivityListener(this);
         // Allow plugins to reference the VolumeDialogController.
-        Dependency.get(PluginDependencyProvider.class)
-                .allowPluginDependency(VolumeDialogController.class);
-        Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
+        pluginDependencyProvider.allowPluginDependency(VolumeDialogController.class);
+        extensionController.newExtension(VolumeDialog.class)
                 .withPlugin(VolumeDialog.class)
-                .withDefault(this::createDefault)
+                .withDefault(() -> volumeDialog)
                 .withCallback(dialog -> {
                     if (mDialog != null) {
                         mDialog.destroy();
@@ -99,19 +103,11 @@
                     mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
                 }).build();
         applyConfiguration();
-        Dependency.get(TunerService.class).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
+        tunerService.addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
                 VOLUME_SILENT_DO_NOT_DISTURB);
         demoModeController.addCallback(this);
     }
 
-    protected VolumeDialog createDefault() {
-        VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
-        impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
-        impl.setAutomute(true);
-        impl.setSilentMode(false);
-        return impl;
-    }
-
     @Override
     public void onTuningChanged(String key, String newValue) {
         boolean volumeDownToEnterSilent = mVolumePolicy.volumeDownToEnterSilent;
@@ -189,8 +185,7 @@
     }
 
     private void startSettings(Intent intent) {
-        Dependency.get(ActivityStarter.class).startActivity(intent,
-                true /* onlyProvisioned */, true /* dismissShade */);
+        mActivityStarter.startActivity(intent, true /* onlyProvisioned */, true /* dismissShade */);
     }
 
     private final VolumeDialogImpl.Callback mVolumeDialogCallback = new VolumeDialogImpl.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index f317628..58f74a0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -106,7 +106,6 @@
 import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
 import com.android.internal.view.RotationPolicy;
 import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -235,6 +234,10 @@
     private final Object mSafetyWarningLock = new Object();
     private final Accessibility mAccessibility = new Accessibility();
 
+    private final ConfigurationController mConfigurationController;
+    private final MediaOutputDialogFactory mMediaOutputDialogFactory;
+    private final ActivityStarter mActivityStarter;
+
     private boolean mShowing;
     private boolean mShowA11yStream;
 
@@ -256,14 +259,24 @@
     private Consumer<Boolean> mCrossWindowBlurEnabledListener;
     private BackgroundBlurDrawable mDialogRowsViewBackground;
 
-    public VolumeDialogImpl(Context context) {
+    public VolumeDialogImpl(
+            Context context,
+            VolumeDialogController volumeDialogController,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            DeviceProvisionedController deviceProvisionedController,
+            ConfigurationController configurationController,
+            MediaOutputDialogFactory mediaOutputDialogFactory,
+            ActivityStarter activityStarter) {
         mContext =
                 new ContextThemeWrapper(context, R.style.volume_dialog_theme);
-        mController = Dependency.get(VolumeDialogController.class);
+        mController = volumeDialogController;
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
-        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+        mAccessibilityMgr = accessibilityManagerWrapper;
+        mDeviceProvisionedController = deviceProvisionedController;
+        mConfigurationController = configurationController;
+        mMediaOutputDialogFactory = mediaOutputDialogFactory;
+        mActivityStarter = activityStarter;
         mShowActiveStreamOnly = showActiveStreamOnly();
         mHasSeenODICaptionsTooltip =
                 Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false);
@@ -306,14 +319,14 @@
         mController.addCallback(mControllerCallbackH, mHandler);
         mController.getState();
 
-        Dependency.get(ConfigurationController.class).addCallback(this);
+        mConfigurationController.addCallback(this);
     }
 
     @Override
     public void destroy() {
         mController.removeCallback(mControllerCallbackH);
         mHandler.removeCallbacksAndMessages(null);
-        Dependency.get(ConfigurationController.class).removeCallback(this);
+        mConfigurationController.removeCallback(this);
     }
 
     @Override
@@ -1017,9 +1030,8 @@
                 Events.writeEvent(Events.EVENT_SETTINGS_CLICK);
                 Intent intent = new Intent(Settings.Panel.ACTION_VOLUME);
                 dismissH(DISMISS_REASON_SETTINGS_CLICKED);
-                Dependency.get(MediaOutputDialogFactory.class).dismiss();
-                Dependency.get(ActivityStarter.class).startActivity(intent,
-                        true /* dismissShade */);
+                mMediaOutputDialogFactory.dismiss();
+                mActivityStarter.startActivity(intent, true /* dismissShade */);
             });
         }
     }
@@ -2255,6 +2267,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/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index 1ef4c16..79aa643 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -16,11 +16,23 @@
 
 package com.android.systemui.volume.dagger;
 
+import android.content.Context;
+import android.media.AudioManager;
+
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.VolumeDialog;
+import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
+import com.android.systemui.volume.VolumeDialogImpl;
 
 import dagger.Binds;
 import dagger.Module;
+import dagger.Provides;
 
 
 /** Dagger Module for code in the volume package. */
@@ -29,4 +41,28 @@
     /** */
     @Binds
     VolumeComponent provideVolumeComponent(VolumeDialogComponent volumeDialogComponent);
+
+    /** */
+    @Provides
+    static VolumeDialog provideVolumeDialog(
+            Context context,
+            VolumeDialogController volumeDialogController,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            DeviceProvisionedController deviceProvisionedController,
+            ConfigurationController configurationController,
+            MediaOutputDialogFactory mediaOutputDialogFactory,
+            ActivityStarter activityStarter) {
+        VolumeDialogImpl impl = new VolumeDialogImpl(
+                context,
+                volumeDialogController,
+                accessibilityManagerWrapper,
+                deviceProvisionedController,
+                configurationController,
+                mediaOutputDialogFactory,
+                activityStarter);
+        impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
+        impl.setAutomute(true);
+        impl.setSilentMode(false);
+        return impl;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 39a8bd9..dbdc460 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -25,6 +25,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
@@ -58,10 +59,10 @@
     @WMSingleton
     @Provides
     static DisplayImeController provideDisplayImeController(IWindowManager wmService,
-            DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor,
-            TransactionPool transactionPool) {
-        return new DisplayImeController(wmService, displayController, mainExecutor,
-                transactionPool);
+            DisplayController displayController, DisplayInsetsController displayInsetsController,
+            @ShellMainThread ShellExecutor mainExecutor, TransactionPool transactionPool) {
+        return new DisplayImeController(wmService, displayController, displayInsetsController,
+                mainExecutor, transactionPool);
     }
 
     //
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 7e733a9..f420a85 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -44,6 +44,7 @@
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
@@ -55,6 +56,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;
@@ -109,6 +111,14 @@
 
     @WMSingleton
     @Provides
+    static DisplayInsetsController provideDisplayInsetsController( IWindowManager wmService,
+            DisplayController displayController,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        return new DisplayInsetsController(wmService, displayController, mainExecutor);
+    }
+
+    @WMSingleton
+    @Provides
     static DisplayLayout provideDisplayLayout() {
         return new DisplayLayout();
     }
@@ -116,8 +126,8 @@
     @WMSingleton
     @Provides
     static DragAndDropController provideDragAndDropController(Context context,
-            DisplayController displayController) {
-        return new DragAndDropController(context, displayController);
+            DisplayController displayController, UiEventLogger uiEventLogger) {
+        return new DragAndDropController(context, displayController, uiEventLogger);
     }
 
     @WMSingleton
@@ -213,6 +223,13 @@
     }
 
     //
+    // Freeform (optional feature)
+    //
+
+    @BindsOptionalOf
+    abstract Optional<FreeformTaskListener> optionalFreeformTaskListener();
+
+    //
     // Hide display cutout
     //
 
@@ -328,9 +345,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);
     }
 
     //
@@ -358,11 +377,13 @@
             SyncTransactionQueue syncQueue, Context context,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             @ShellMainThread ShellExecutor mainExecutor,
-            DisplayImeController displayImeController, Transitions transitions,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController, Transitions transitions,
             TransactionPool transactionPool) {
         if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
             return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
-                    rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, transitions,
+                    rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController,
+                    displayInsetsController, transitions,
                     transactionPool));
         } else {
             return Optional.empty();
@@ -442,7 +463,9 @@
 
     @WMSingleton
     @Provides
-    static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
+    static ShellInitImpl provideShellInitImpl(DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<BubbleController> bubblesOptional,
@@ -451,10 +474,13 @@
             Optional<AppPairsController> appPairsOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Optional<Optional<FreeformTaskListener>> freeformTaskListener,
             Transitions transitions,
             StartingWindowController startingWindow,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return new ShellInitImpl(displayImeController,
+        return new ShellInitImpl(displayController,
+                displayImeController,
+                displayInsetsController,
                 dragAndDropController,
                 shellTaskOrganizer,
                 bubblesOptional,
@@ -463,6 +489,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..83c2a9b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -28,6 +28,7 @@
 import com.android.wm.shell.apppairs.AppPairsController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -36,6 +37,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;
@@ -82,10 +84,23 @@
     @WMSingleton
     @Provides
     static DisplayImeController provideDisplayImeController(IWindowManager wmService,
-            DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor,
+            DisplayController displayController, DisplayInsetsController displayInsetsController,
+            @ShellMainThread ShellExecutor mainExecutor,
             TransactionPool transactionPool) {
-        return new DisplayImeController(wmService, displayController, mainExecutor,
-                transactionPool);
+        return new DisplayImeController(wmService, displayController, displayInsetsController,
+                mainExecutor, transactionPool);
+    }
+
+    //
+    // Freeform
+    //
+
+    @WMSingleton
+    @Provides
+    static Optional<FreeformTaskListener> provideFreeformTaskListener(
+            Context context,
+            SyncTransactionQueue syncQueue) {
+        return Optional.ofNullable(FreeformTaskListener.create(context, syncQueue));
     }
 
     //
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index f1c687f..763a5cb 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -93,10 +93,17 @@
         <activity android:name="com.android.systemui.screenshot.RecyclerViewActivity"
                   android:exported="false" />
 
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbPermissionActivityTest$UsbPermissionActivityTestable"
+                  android:exported="false"
+                  android:theme="@style/Theme.SystemUI.Dialog.Alert"
+                  android:finishOnCloseSystemDialogs="true"
+                  android:excludeFromRecents="true" />
+
         <provider
-            android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
+            android:name="androidx.startup.InitializationProvider"
             tools:replace="android:authorities"
-            android:authorities="${applicationId}.lifecycle-tests"
+            android:authorities="${applicationId}.startup-tests"
             android:exported="false"
             android:enabled="false"
             android:multiprocess="true" />
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index ce65733..06b0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -19,6 +19,7 @@
 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;
@@ -28,7 +29,6 @@
 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,8 +104,6 @@
     private AnimatableClockView mLargeClockView;
     @Mock
     private FrameLayout mLargeClockFrame;
-    @Mock
-    private ViewGroup mSmartspaceContainer;
 
     private final View mFakeSmartspaceView = new View(mContext);
 
@@ -125,8 +123,6 @@
         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());
 
@@ -214,7 +210,7 @@
 
     @Test
     public void testSmartspaceEnabledRemovesKeyguardStatusArea() {
-        when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
+        when(mSmartspaceController.isEnabled()).thenReturn(true);
         when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
         mController.init();
 
@@ -223,7 +219,7 @@
 
     @Test
     public void testSmartspaceDisabledShowsKeyguardStatusArea() {
-        when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(false);
+        when(mSmartspaceController.isEnabled()).thenReturn(false);
         mController.init();
 
         assertEquals(View.VISIBLE, mStatusArea.getVisibility());
@@ -231,16 +227,17 @@
 
     @Test
     public void testDetachRemovesSmartspaceView() {
-        when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
+        when(mSmartspaceController.isEnabled()).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(mSmartspaceContainer).removeAllViews();
+        verify(mView).removeView(mFakeSmartspaceView);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
new file mode 100644
index 0000000..db87c5d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.keyguard
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class KeyguardListenQueueTest : SysuiTestCase() {
+
+    @Test
+    fun testQueueIsBounded() {
+        val size = 5
+        val queue = KeyguardListenQueue(sizePerModality = size)
+
+        val fingerprints = List(100) { fingerprintModel(it) }
+        fingerprints.forEach { queue.add(it) }
+
+        assertThat(queue.models).containsExactlyElementsIn(fingerprints.takeLast(size))
+
+        val faces = List(100) { faceModel(it) }
+        faces.forEach { queue.add(it) }
+
+        assertThat(queue.models).containsExactlyElementsIn(
+            faces.takeLast(size) + fingerprints.takeLast(5)
+        )
+
+        repeat(100) {
+            queue.add(faceModel(-1))
+            queue.add(fingerprintModel(-1))
+        }
+        assertThat(queue.models).hasSize(2 * size)
+        assertThat(queue.models.count { it.userId == -1 }).isEqualTo(2 * size)
+    }
+}
+
+private fun fingerprintModel(user: Int) = KeyguardFingerprintListenModel(
+    timeMillis = System.currentTimeMillis(),
+    userId = user,
+    listening = false,
+    biometricEnabledForUser = false,
+    bouncer = false,
+    canSkipBouncer = false,
+    credentialAttempted = false,
+    deviceInteractive = false,
+    dreaming = false,
+    encryptedOrLockdown = false,
+    fingerprintDisabled = false,
+    fingerprintLockedOut = false,
+    goingToSleep = false,
+    keyguardGoingAway = false,
+    keyguardIsVisible = false,
+    keyguardOccluded = false,
+    occludingAppRequestingFp = false,
+    primaryUser = false,
+    shouldListenForFingerprintAssistant = false,
+    switchingUser = false,
+    udfps = false,
+    userDoesNotHaveTrust = false,
+    userNeedsStrongAuth = false
+)
+
+private fun faceModel(user: Int) = KeyguardFaceListenModel(
+    timeMillis = System.currentTimeMillis(),
+    userId = user,
+    listening = false,
+    authInterruptActive = false,
+    becauseCannotSkipBouncer = false,
+    biometricSettingEnabledForUser = false,
+    bouncer = false,
+    faceAuthenticated = false,
+    faceDisabled = false,
+    keyguardAwake = false,
+    keyguardGoingAway = false,
+    listeningForFaceAssistant = false,
+    lockIconPressed = false,
+    occludingAppRequestingFaceAuth = false,
+    primaryUser = false,
+    scanningAllowedByStrongAuth = false,
+    secureCameraLaunched = false,
+    switchingUser = false
+)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 0276323..2efd369 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -165,7 +165,8 @@
 
         mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
                 /* leftAligned= */false, /* animate= */false);
-        verify(mSecurityViewFlipper).setTranslationX(SCREEN_WIDTH / 2.0f);
+        verify(mSecurityViewFlipper).setTranslationX(
+                mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
 
         mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
                 /* leftAligned= */true, /* animate= */false);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 6ec14fe..9c2382d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,6 +22,7 @@
 import android.testing.AndroidTestingRunner;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
 import com.android.systemui.statusbar.phone.DozeParameters;
@@ -50,6 +51,8 @@
     @Mock
     private KeyguardStateController mKeyguardStateController;
     @Mock
+    private CommunalStateController mCommunalStateController;
+    @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
     ConfigurationController mConfigurationController;
@@ -76,6 +79,7 @@
                 mKeyguardClockSwitchController,
                 mKeyguardStateController,
                 mKeyguardUpdateMonitor,
+                mCommunalStateController,
                 mConfigurationController,
                 mDozeParameters,
                 mKeyguardUnlockAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
new file mode 100644
index 0000000..1efcbd6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.keyguard;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.communal.CommunalStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class KeyguardVisibilityHelperTest extends SysuiTestCase {
+    @Mock
+    private CommunalStateController mCommunalStateController;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    com.android.systemui.statusbar.phone.DozeParameters mDozeParameters;
+    @Mock
+    UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock
+    ViewPropertyAnimator mViewPropertyAnimator;
+    @Mock
+    View mTargetView;
+
+    private KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mTargetView.animate()).thenReturn(mViewPropertyAnimator);
+        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
+                mCommunalStateController, mKeyguardStateController, mDozeParameters,
+                mUnlockedScreenOffAnimationController, false, false);
+    }
+
+    @Test
+    public void testHideOnCommunal() {
+        // Verify view is hidden when communal is visible.
+        when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
+        mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
+                false, StatusBarState.KEYGUARD);
+        verify(mTargetView).setVisibility(View.GONE);
+        verify(mTargetView).setAlpha(1.0f);
+
+        // Verify view is shown when communal is not visible.
+        when(mCommunalStateController.getCommunalViewShowing()).thenReturn(false);
+        mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
+                false, StatusBarState.KEYGUARD);
+        verify(mTargetView).setVisibility(View.VISIBLE);
+    }
+
+    @Test
+    public void testVisibleOnCommunal() {
+        when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
+        when(mKeyguardStateController.isOccluded()).thenReturn(false);
+
+        // Verify that helpers constructed with visibility on communal are not hidden when communal
+        // is present.
+        mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
+                mCommunalStateController, mKeyguardStateController, mDozeParameters,
+                mUnlockedScreenOffAnimationController, false, true);
+        mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
+                false, StatusBarState.KEYGUARD);
+        verify(mTargetView).setVisibility(View.VISIBLE);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index ed5cbe2..afbd2f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -43,6 +43,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -60,7 +61,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.R.dimen;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
@@ -100,6 +100,8 @@
     private UserTracker mUserTracker;
     @Mock
     private PrivacyDotViewController mDotViewController;
+    @Mock
+    private TypedArray mMockTypedArray;
 
     @Before
     public void setup() {
@@ -121,6 +123,7 @@
                 .getDisplay(DEFAULT_DISPLAY);
         when(mDisplayManager.getDisplay(anyInt())).thenReturn(display);
         mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
+        when(mMockTypedArray.length()).thenReturn(0);
 
         mScreenDecorations = spy(new ScreenDecorations(mContext, mExecutor, mSecureSettings,
                 mBroadcastDispatcher, mTunerService, mUserTracker, mDotViewController,
@@ -148,18 +151,9 @@
 
     @Test
     public void testNoRounding_NoCutout() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
 
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
@@ -173,14 +167,9 @@
 
     @Test
     public void testRounding_NoCutout() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                20 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
 
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
@@ -203,19 +192,10 @@
 
     @Test
     public void testRoundingRadius_NoCutout() {
-        final int testRadius = 1;
         final Point testRadiusPoint = new Point(1, 1);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, testRadius);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, testRadius);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, testRadius);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
-
+        setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
 
@@ -230,16 +210,8 @@
     public void testRoundingTopBottomRadius_OnTopBottomOverlay() {
         final int testTopRadius = 1;
         final int testBottomRadius = 5;
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, testTopRadius);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, testTopRadius);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, testBottomRadius);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */,
+                false /* multipleRadius */, false /* fillCutout */);
 
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
@@ -267,16 +239,8 @@
     public void testRoundingTopBottomRadius_OnLeftRightOverlay() {
         final int testTopRadius = 1;
         final int testBottomRadius = 5;
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, testTopRadius);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, testTopRadius);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, testBottomRadius);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */,
+                false /* multipleRadius */, false /* fillCutout */);
 
         // left cutout
         doReturn(new DisplayCutout(
@@ -310,15 +274,9 @@
     public void testRoundingMultipleRadius_NoCutout() {
         final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
         final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight());
-
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 9999);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 9999);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, true);
+        setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                9999 /* roundedPadding */, true /* multipleRadius */,
+                false /* fillCutout */);
 
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
@@ -345,27 +303,18 @@
 
     @Test
     public void testNoRounding_CutoutShortEdge() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                true /* fillCutout */);
 
         // top cutout
         doReturn(new DisplayCutout(
-                        Insets.of(0, 10, 0, 0),
-                        ZERO_RECT,
-                        new Rect(9, 0, 10, 1),
-                        ZERO_RECT,
-                        ZERO_RECT,
-                        Insets.NONE)).when(mScreenDecorations).getCutout();
+                Insets.of(0, 10, 0, 0),
+                ZERO_RECT,
+                new Rect(9, 0, 10, 1),
+                ZERO_RECT,
+                ZERO_RECT,
+                Insets.NONE)).when(mScreenDecorations).getCutout();
 
         mScreenDecorations.start();
         // Top window is created for top cutout.
@@ -381,18 +330,9 @@
 
     @Test
     public void testNoRounding_CutoutLongEdge() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                true /* fillCutout */);
 
         // left cutout
         doReturn(new DisplayCutout(
@@ -417,14 +357,9 @@
 
     @Test
     public void testRounding_CutoutShortEdge() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                20 /* roundedPadding */, false /* multipleRadius */,
+                true /* fillCutout */);
 
         // top cutout
         doReturn(new DisplayCutout(
@@ -450,14 +385,9 @@
 
     @Test
     public void testRounding_CutoutLongEdge() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                20 /* roundedPadding */, false /* multipleRadius */,
+                true /* fillCutout */);
 
         // left cutout
         doReturn(new DisplayCutout(
@@ -483,14 +413,9 @@
 
     @Test
     public void testRounding_CutoutShortAndLongEdge() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                20 /* roundedPadding */, false /* multipleRadius */,
+                true /* fillCutout */);
 
         // top and left cutout
         doReturn(new DisplayCutout(
@@ -517,18 +442,9 @@
 
     @Test
     public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                true /* fillCutout */);
 
         // Set to short edge cutout(top).
         doReturn(new DisplayCutout(
@@ -566,18 +482,9 @@
 
     @Test
     public void testDelayedCutout() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(dimen.rounded_corner_content_padding, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
 
         // top cutout
         doReturn(new DisplayCutout(
@@ -591,8 +498,9 @@
         mScreenDecorations.start();
         assertNull(mScreenDecorations.mOverlays);
 
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
+        when(mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
+                .thenReturn(true);
         mScreenDecorations.onConfigurationChanged(new Configuration());
 
         // Only top windows should be added.
@@ -612,34 +520,24 @@
 
     @Test
     public void testUpdateRoundedCorners() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
 
         mScreenDecorations.start();
         assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20));
 
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 5);
+        when(mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.rounded_corner_radius)).thenReturn(5);
         mScreenDecorations.onConfigurationChanged(null);
         assertEquals(mScreenDecorations.mRoundedDefault, new Point(5, 5));
     }
 
     @Test
     public void testOnlyRoundedCornerRadiusTop() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 10);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
 
         mScreenDecorations.start();
         assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
@@ -649,16 +547,9 @@
 
     @Test
     public void testOnlyRoundedCornerRadiusBottom() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.dimen.rounded_corner_radius_bottom, 20);
-        mContext.getOrCreateTestableResources()
-                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+        setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */,
+                0 /* roundedPadding */, false /* multipleRadius */,
+                false /* fillCutout */);
 
         mScreenDecorations.start();
         assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
@@ -721,4 +612,44 @@
         verify(mTunerService, times(1)).removeTunable(any());
         assertThat(mScreenDecorations.mIsRegistered, is(false));
     }
+
+    private void setupResources(int radius, int radiusTop, int radiusBottom, int roundedPadding,
+            boolean multipleRadius, boolean fillCutout) {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.array.config_displayUniqueIdArray,
+                new String[]{});
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.array.config_roundedCornerRadiusArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.array.config_roundedCornerTopRadiusArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.array.config_roundedCornerBottomRadiusArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.array.config_roundedCornerDrawableArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.array.config_roundedCornerTopDrawableArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.array.config_roundedCornerBottomDrawableArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.array.config_roundedCornerMultipleRadiusArray,
+                mMockTypedArray);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, radius);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius_top, radiusTop);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius_bottom, radiusBottom);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.dimen.rounded_corner_content_padding, roundedPadding);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.bool.config_roundedCornerMultipleRadius, multipleRadius);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index ca65330..b27f5b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -169,6 +169,29 @@
     }
 
     @Test
+    public void enableWindowMagnification_LargeScreen_windowSizeIsConstrained() {
+        final int screenSize = mContext.getResources().getDimensionPixelSize(
+                R.dimen.magnification_max_frame_size) * 10;
+        mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
+        //We need to initialize new one because the window size is determined when initialization.
+        final WindowMagnificationController controller = new WindowMagnificationController(mContext,
+                mHandler, mSfVsyncFrameProvider,
+                mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
+
+        mInstrumentation.runOnMainSync(() -> {
+            controller.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        final int halfScreenSize = screenSize / 2;
+        WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView();
+        // The frame size should be the half of smaller value of window height/width unless it
+        //exceed the max frame size.
+        assertTrue(params.width < halfScreenSize);
+        assertTrue(params.height < halfScreenSize);
+    }
+
+    @Test
     public void deleteWindowMagnification_destroyControl() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -186,6 +209,7 @@
     public void deleteWindowMagnification_enableAtTheBottom_overlapFlagIsFalse() {
         final WindowManager wm = mContext.getSystemService(WindowManager.class);
         final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
+        setSystemGestureInsets();
 
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -249,7 +273,9 @@
     @Test
     public void onOrientationChanged_enabled_updateDisplayRotationAndCenterStayAtSamePosition() {
         final Display display = Mockito.spy(mContext.getDisplay());
-        when(display.getRotation()).thenReturn(Surface.ROTATION_90);
+        final int currentRotation = display.getRotation();
+        final int newRotation = (currentRotation + 1) % 4;
+        when(display.getRotation()).thenReturn(newRotation);
         when(mContext.getDisplay()).thenReturn(display);
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -258,7 +284,7 @@
         final PointF expectedCenter = new PointF(mWindowMagnificationController.getCenterY(),
                 mWindowMagnificationController.getCenterX());
         final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
-        // Rotate the window 90 degrees.
+        // Rotate the window clockwise 90 degree.
         windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
                 windowBounds.right);
         mWindowManager.setWindowBounds(windowBounds);
@@ -267,7 +293,7 @@
             mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
         });
 
-        assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
+        assertEquals(newRotation, mWindowMagnificationController.mRotation);
         final PointF actualCenter = new PointF(mWindowMagnificationController.getCenterX(),
                 mWindowMagnificationController.getCenterY());
         assertEquals(expectedCenter, actualCenter);
@@ -313,6 +339,27 @@
                 mWindowMagnificationController.getCenterY() / testWindowBounds.height(),
                 0);
     }
+    @Test
+    public void screenSizeIsChangedToLarge_enabled_windowSizeIsConstrained() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+        final int screenSize = mContext.getResources().getDimensionPixelSize(
+                R.dimen.magnification_max_frame_size) * 10;
+        mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+        });
+
+        final int halfScreenSize = screenSize / 2;
+        WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView();
+        // The frame size should be the half of smaller value of window height/width unless it
+        //exceed the max frame size.
+        assertTrue(params.width < halfScreenSize);
+        assertTrue(params.height < halfScreenSize);
+    }
 
     @Test
     public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
@@ -461,10 +508,7 @@
     @Test
     public void moveWindowMagnificationToTheBottom_enabledWithGestureInset_overlapFlagIsTrue() {
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
-        final WindowInsets testInsets = new WindowInsets.Builder()
-                .setInsets(systemGestures(), Insets.of(0, 0, 0, 10))
-                .build();
-        mWindowManager.setWindowInsets(testInsets);
+        setSystemGestureInsets();
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                     Float.NaN);
@@ -490,4 +534,11 @@
     private boolean hasMagnificationOverlapFlag() {
         return (mSysUiState.getFlags() & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0;
     }
+
+    private void setSystemGestureInsets() {
+        final WindowInsets testInsets = new WindowInsets.Builder()
+                .setInsets(systemGestures(), Insets.of(0, 0, 0, 10))
+                .build();
+        mWindowManager.setWindowInsets(testInsets);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
index 06e27b5..f09d7b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.View.OVER_SCROLL_ALWAYS;
 import static android.view.View.OVER_SCROLL_NEVER;
 import static android.view.WindowInsets.Type.ime;
@@ -134,7 +135,10 @@
         mMenuHalfHeight = menuHeight / 2;
         mScreenHalfWidth = screenWidth / 2;
         mScreenHalfHeight = mScreenHeight / 2;
-        mMaxWindowX = screenWidth - margin - menuWidth;
+        int marginStartEnd =
+                mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT
+                        ? margin : 0;
+        mMaxWindowX = screenWidth - marginStartEnd - menuWidth;
         mMenuWindowHeight = menuHeight + margin * 2;
         mMaxWindowY = mScreenHeight - mMenuWindowHeight;
     }
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..1d038a4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.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.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.BatteryController;
+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;
+    @Mock
+    private BatteryController mBatteryController;
+
+    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,
+                mBatteryController
+        );
+    }
+
+    @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()
+        );
+        verify(mBatteryController).addCallback(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());
+        verify(mBatteryController).removeCallback(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/battery/BatteryMeterViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
new file mode 100644
index 0000000..b4ff2a5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
@@ -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.battery
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.battery.BatteryMeterView.BatteryEstimateFetcher
+import com.android.systemui.statusbar.policy.BatteryController.EstimateFetchCompletion
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class BatteryMeterViewTest : SysuiTestCase() {
+
+    private lateinit var mBatteryMeterView: BatteryMeterView
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        mBatteryMeterView = BatteryMeterView(mContext, null)
+    }
+
+    @Test
+    fun updatePercentText_estimateModeAndNotCharging_estimateFetched() {
+        mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
+        mBatteryMeterView.setBatteryEstimateFetcher(Fetcher())
+
+        mBatteryMeterView.updatePercentText()
+
+        assertThat(mBatteryMeterView.batteryPercentViewText).isEqualTo(ESTIMATE)
+    }
+
+    @Test
+    fun updatePercentText_noBatteryEstimateFetcher_noCrash() {
+        mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
+
+        mBatteryMeterView.updatePercentText()
+        // No assert needed
+    }
+
+    private class Fetcher : BatteryEstimateFetcher {
+        override fun fetchBatteryTimeRemainingEstimate(
+                completion: EstimateFetchCompletion) {
+            completion.onBatteryRemainingEstimateRetrieved(ESTIMATE)
+        }
+    }
+
+    private companion object {
+        const val ESTIMATE = "2 hours 2 minutes"
+    }
+}
\ No newline at end of file
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 e478b1a..b6d1e42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -102,7 +102,7 @@
         mFaceToFpView.onDialogAnimatedIn();
         verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
     }
 
     @Test
@@ -110,13 +110,13 @@
         mFaceToFpView.onDialogAnimatedIn();
         verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
 
         mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
         verify(mFaceToFpView.mFaceIconController).updateState(
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
-        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
 
         assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
     }
@@ -131,14 +131,12 @@
 
         verify(mFaceToFpView.mFaceIconController).deactivate();
         verify(mFaceToFpView.mUdfpsIconController).updateState(
-                eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
-                eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
+                eq(AuthBiometricFaceToFingerprintView.STATE_IDLE));
         verify(mConfirmButton).setVisibility(eq(View.GONE));
 
         mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
 
         verify(mFaceToFpView.mUdfpsIconController).updateState(
-                eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 39d5314..8dd5d6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -565,8 +565,9 @@
                 credentialAllowed,
                 true /* requireConfirmation */,
                 0 /* userId */,
-                "testPackage",
                 0 /* operationId */,
+                "testPackage",
+                1 /* requestId */,
                 BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT);
     }
 
@@ -612,7 +613,7 @@
         @Override
         protected AuthDialog buildDialog(PromptInfo promptInfo,
                 boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed,
-                String opPackageName, boolean skipIntro, long operationId,
+                String opPackageName, boolean skipIntro, long operationId, long requestId,
                 @BiometricManager.BiometricMultiSensorMode int multiSensorConfig) {
 
             mLastBiometricPromptInfo = promptInfo;
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 9098e44..f5c6f98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.biometrics;
 
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
+
 import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -69,6 +71,7 @@
 import com.android.systemui.util.concurrency.FakeExecution;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.time.SystemClock;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -147,6 +150,8 @@
     private Handler mHandler;
     @Mock
     private ConfigurationController mConfigurationController;
+    @Mock
+    private SystemClock mSystemClock;
 
     private FakeExecutor mFgExecutor;
 
@@ -229,7 +234,8 @@
                 mKeyguardBypassController,
                 mDisplayManager,
                 mHandler,
-                mConfigurationController);
+                mConfigurationController,
+                mSystemClock);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -413,6 +419,21 @@
     }
 
     @Test
+    public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
+        // GIVEN overlay was showing and the udfps bouncer is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
+
+        // WHEN the overlay is hidden
+        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+        mFgExecutor.runAllReady();
+
+        // THEN the udfps bouncer is reset
+        verify(mStatusBarKeyguardViewManager).resetAlternateAuth(eq(true));
+    }
+
+    @Test
     public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
                 IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
@@ -544,5 +565,10 @@
                 eq(mUdfpsController.EFFECT_CLICK),
                 eq("udfps-onStart"),
                 eq(UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES));
+
+        // THEN make sure vibration attributes has so that it always will play the haptic,
+        // even in battery saver mode
+        assertEquals(USAGE_ASSISTANCE_ACCESSIBILITY,
+                UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES.getUsage());
     }
 }
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 cc34c30..2c08fe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -18,8 +18,13 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+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.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -30,7 +35,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -40,7 +44,9 @@
 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.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,6 +57,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Optional;
+import java.util.List;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -76,11 +83,14 @@
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
     private KeyguardViewMediator mKeyguardViewMediator;
     @Mock
     private ConfigurationController mConfigurationController;
     @Mock
     private UdfpsController mUdfpsController;
+    private FakeSystemClock mSystemClock = new FakeSystemClock();
 
     private UdfpsKeyguardViewController mController;
 
@@ -89,14 +99,15 @@
     private StatusBarStateController.StateListener mStatusBarStateListener;
 
     @Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
-    private StatusBar.ExpansionChangedListener mExpansionListener;
+    private List<StatusBar.ExpansionChangedListener> mExpansionListeners;
 
     @Captor private ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
             mAltAuthInterceptorCaptor;
     private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor;
 
-    @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateMonitorCallbackCaptor;
-    private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+    @Captor private ArgumentCaptor<KeyguardStateController.Callback>
+            mKeyguardStateControllerCallbackCaptor;
+    private KeyguardStateController.Callback mKeyguardStateControllerCallback;
 
     @Before
     public void setUp() {
@@ -115,13 +126,15 @@
                 mKeyguardViewMediator,
                 mLockscreenShadeTransitionController,
                 mConfigurationController,
+                mSystemClock,
+                mKeyguardStateController,
                 mUdfpsController);
     }
 
     @Test
     public void testRegistersExpansionChangedListenerOnAttached() {
         mController.onViewAttached();
-        captureExpansionListener();
+        captureExpansionListeners();
     }
 
     @Test
@@ -150,11 +163,15 @@
     public void testListenersUnregisteredOnDetached() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
+        captureExpansionListeners();
+        captureKeyguardStateControllerCallback();
         mController.onViewDetached();
 
         verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
-        verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
+        for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+            verify(mStatusBar).removeExpansionChangedListener(listener);
+        }
+        verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
     }
 
     @Test
@@ -173,7 +190,6 @@
     public void testShouldPauseAuthBouncerShowing() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
 
@@ -184,7 +200,6 @@
     public void testShouldNotPauseAuthOnKeyguard() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
 
@@ -192,10 +207,25 @@
     }
 
     @Test
+    public void testShouldPauseAuthIsLaunchTransitionFadingAway() {
+        // GIVEN view is attached and we're on the keyguard (see testShouldNotPauseAuthOnKeyguard)
+        mController.onViewAttached();
+        captureStatusBarStateListeners();
+        sendStatusBarStateChanged(StatusBarState.KEYGUARD);
+
+        // WHEN isLaunchTransitionFadingAway=true
+        captureKeyguardStateControllerCallback();
+        when(mKeyguardStateController.isLaunchTransitionFadingAway()).thenReturn(true);
+        mKeyguardStateControllerCallback.onLaunchTransitionFadingAwayChanged();
+
+        // THEN pause auth
+        assertTrue(mController.shouldPauseAuth());
+    }
+
+    @Test
     public void testShouldPauseAuthOnShadeLocked() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
 
@@ -206,7 +236,6 @@
     public void testShouldPauseAuthOnShade() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         // WHEN not on keyguard yet (shade = home)
         sendStatusBarStateChanged(StatusBarState.SHADE);
@@ -219,7 +248,6 @@
     public void testShouldPauseAuthAnimatingScreenOffFromShade() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         // WHEN transitioning from home/shade => keyguard + animating screen off
         mStatusBarStateListener.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD);
@@ -233,7 +261,6 @@
     public void testDoNotPauseAuthAnimatingScreenOffFromLS() {
         mController.onViewAttached();
         captureStatusBarStateListeners();
-        captureExpansionListener();
 
         // WHEN animating screen off transition from LS => AOD
         sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -274,6 +301,93 @@
         verify(mStatusBarKeyguardViewManager).removeAlternateAuthInterceptor(mAltAuthInterceptor);
     }
 
+    @Test
+    public void testHiddenUdfpsBouncerOnTouchOutside_nothingHappens() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureAltAuthInterceptor();
+
+        // GIVEN udfps bouncer isn't showing
+        mAltAuthInterceptor.hideAlternateAuthBouncer();
+
+        // WHEN touch is observed outside the view
+        mController.onTouchOutsideView();
+
+        // THEN bouncer / alt auth methods are never called
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+        verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean());
+    }
+
+    @Test
+    public void testShowingUdfpsBouncerOnTouchOutsideWithinThreshold_nothingHappens() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureAltAuthInterceptor();
+
+        // GIVEN udfps bouncer is showing
+        mAltAuthInterceptor.showAlternateAuthBouncer();
+
+        // WHEN touch is observed outside the view 200ms later (just within threshold)
+        mSystemClock.advanceTime(200);
+        mController.onTouchOutsideView();
+
+        // THEN bouncer / alt auth methods are never called because not enough time has passed
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+        verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean());
+    }
+
+    @Test
+    public void testShowingUdfpsBouncerOnTouchOutsideAboveThreshold_showInputBouncer() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureAltAuthInterceptor();
+
+        // GIVEN udfps bouncer is showing
+        mAltAuthInterceptor.showAlternateAuthBouncer();
+
+        // WHEN touch is observed outside the view 205ms later
+        mSystemClock.advanceTime(205);
+        mController.onTouchOutsideView();
+
+        // THEN show the bouncer and reset alt auth
+        verify(mStatusBarKeyguardViewManager).showBouncer(eq(true));
+        verify(mStatusBarKeyguardViewManager).resetAlternateAuth(anyBoolean());
+    }
+
+    @Test
+    public void testFadeInWithStatusBarExpansion() {
+        // GIVEN view is attached
+        mController.onViewAttached();
+        captureExpansionListeners();
+        captureKeyguardStateControllerCallback();
+        reset(mView);
+
+        // WHEN status bar expansion is 0
+        updateStatusBarExpansion(0, true);
+
+        // THEN alpha is 0
+        verify(mView).setUnpausedAlpha(0);
+    }
+
+    @Test
+    public void testShowUdfpsBouncer() {
+        // GIVEN view is attached and status bar expansion is 0
+        mController.onViewAttached();
+        captureExpansionListeners();
+        captureKeyguardStateControllerCallback();
+        captureAltAuthInterceptor();
+        updateStatusBarExpansion(0, true);
+        reset(mView);
+        when(mView.getContext()).thenReturn(mResourceContext);
+        when(mResourceContext.getString(anyInt())).thenReturn("test string");
+
+        // WHEN status bar expansion is 0 but udfps bouncer is requested
+        mAltAuthInterceptor.showAlternateAuthBouncer();
+
+        // THEN alpha is 0
+        verify(mView).setUnpausedAlpha(255);
+    }
+
     private void sendStatusBarStateChanged(int statusBarState) {
         mStatusBarStateListener.onStateChanged(statusBarState);
     }
@@ -283,9 +397,18 @@
         mStatusBarStateListener = mStateListenerCaptor.getValue();
     }
 
-    private void captureExpansionListener() {
-        verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture());
-        mExpansionListener = mExpansionListenerCaptor.getValue();
+    private void captureExpansionListeners() {
+        verify(mStatusBar, times(2))
+                .addExpansionChangedListener(mExpansionListenerCaptor.capture());
+        // first (index=0) is from super class, UdfpsAnimationViewController.
+        // second (index=1) is from UdfpsKeyguardViewController
+        mExpansionListeners = mExpansionListenerCaptor.getAllValues();
+    }
+
+    private void updateStatusBarExpansion(float expansion, boolean expanded) {
+        for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+            listener.onExpansionChanged(expansion, expanded);
+        }
     }
 
     private void captureAltAuthInterceptor() {
@@ -294,8 +417,11 @@
         mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
     }
 
-    private void captureKeyguardUpdateMonitorCallback() {
-        verify(mKeyguardUpdateMonitor).registerCallback(mUpdateMonitorCallbackCaptor.capture());
-        mKeyguardUpdateMonitorCallback = mUpdateMonitorCallbackCaptor.getValue();
+
+
+    private void captureKeyguardStateControllerCallback() {
+        verify(mKeyguardStateController).addCallback(
+                mKeyguardStateControllerCallbackCaptor.capture());
+        mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
     }
 }
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 a22322f..6cfa40a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
@@ -16,6 +16,10 @@
 
 package com.android.systemui.communal;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -28,6 +32,9 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -46,6 +53,9 @@
 @RunWith(AndroidTestingRunner.class)
 public class CommunalHostViewControllerTest extends SysuiTestCase {
     @Mock
+    private CommunalStateController mCommunalStateController;
+
+    @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     @Mock
@@ -57,6 +67,12 @@
     @Mock
     private CommunalHostView mCommunalView;
 
+    @Mock
+    private DozeParameters mDozeParameters;
+
+    @Mock
+    private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+
     private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
 
     private CommunalHostViewController mController;
@@ -64,17 +80,23 @@
     @Mock
     private CommunalSource mCommunalSource;
 
+    @Mock
+    private View mChildView;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
         when(mKeyguardStateController.isShowing()).thenReturn(true);
         when(mCommunalView.isAttachedToWindow()).thenReturn(true);
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
 
-        mController = new CommunalHostViewController(mFakeExecutor, mKeyguardUpdateMonitor,
-                mKeyguardStateController, mStatusBarStateController, mCommunalView);
+        mController = new CommunalHostViewController(mFakeExecutor, mCommunalStateController,
+                mKeyguardUpdateMonitor, mKeyguardStateController, mDozeParameters,
+                mUnlockedScreenOffAnimationController, mStatusBarStateController, mCommunalView);
         mController.init();
         mFakeExecutor.runAllReady();
+
         Mockito.clearInvocations(mCommunalView);
     }
 
@@ -100,33 +122,6 @@
     }
 
     @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);
@@ -152,4 +147,96 @@
         mFakeExecutor.runAllReady();
         verify(mCommunalView).setVisibility(View.VISIBLE);
     }
+
+    @Test
+    public void testReportOcclusion() {
+        // Ensure CommunalHostViewController reports view occluded when either the QS or Shade is
+        // expanded.
+        clearInvocations(mCommunalStateController);
+        mController.updateShadeExpansion(0);
+        verify(mCommunalStateController).setCommunalViewOccluded(false);
+        clearInvocations(mCommunalStateController);
+        mController.updateQsExpansion(.5f);
+        verify(mCommunalStateController).setCommunalViewOccluded(true);
+        clearInvocations(mCommunalStateController);
+        mController.updateShadeExpansion(.7f);
+        verify(mCommunalStateController).setCommunalViewOccluded(true);
+        clearInvocations(mCommunalStateController);
+        mController.updateShadeExpansion(0);
+        verify(mCommunalStateController).setCommunalViewOccluded(true);
+        clearInvocations(mCommunalStateController);
+        mController.updateQsExpansion(0f);
+        verify(mCommunalStateController).setCommunalViewOccluded(false);
+        clearInvocations(mCommunalStateController);
+    }
+
+    @Test
+    public void testCommunalStateControllerHideNotified() {
+        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();
+
+        // Occlude
+        clearInvocations(mCommunalStateController);
+        callbackCapture.getValue().onKeyguardOccludedChanged(true);
+        mFakeExecutor.runAllReady();
+
+        // Verify state controller is notified communal view is hidden.
+        verify(mCommunalStateController).setCommunalViewShowing(false);
+    }
+
+    @Test
+    public void testAlphaPropagation() {
+        final float alpha = 0.8f;
+
+        // Ensure alpha setting is propagated to children.
+        when(mCommunalView.getChildCount()).thenReturn(1);
+        when(mCommunalView.getChildAt(0)).thenReturn(mChildView);
+        mController.setAlpha(alpha);
+        verify(mChildView).setAlpha(alpha);
+        verify(mCommunalView).setAlpha(alpha);
+    }
+
+    @Test
+    public void testMultipleShowRequestSuppression() {
+        // Ensure first request invokes source.
+        mController.show(new WeakReference<>(mCommunalSource));
+        mFakeExecutor.runAllReady();
+        verify(mCommunalSource).requestCommunalView(any());
+        clearInvocations(mCommunalSource);
+
+        // Ensure subsequent identical request is suppressed
+        mController.show(new WeakReference<>(mCommunalSource));
+        mFakeExecutor.runAllReady();
+        verify(mCommunalSource, never()).requestCommunalView(any());
+    }
+
+    @Test
+    public void testNoShowInvocationOnBouncer() {
+        ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
+                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+
+        // Capture callback value for later use.
+        verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
+
+        // Set source so it will be cleared if in invalid state.
+        mController.show(new WeakReference<>(mCommunalSource));
+        mFakeExecutor.runAllReady();
+        clearInvocations(mCommunalStateController, mCommunalView);
+
+        // Change bouncer to showing.
+        callbackCapture.getValue().onKeyguardBouncerChanged(true);
+        mFakeExecutor.runAllReady();
+
+        // Verify that there were no requests to remove all child views or set the communal
+        // state to not showing.
+        verify(mCommunalStateController, never()).setCommunalViewShowing(eq(false));
+        verify(mCommunalView, never()).removeAllViews();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.java
new file mode 100644
index 0000000..0a0266b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.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.communal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.communal.CommunalHostViewPositionAlgorithm.Result;
+
+import org.junit.Test;
+
+
+@SmallTest
+public class CommunalHostViewPositionAlgorithmTest extends SysuiTestCase {
+    @Test
+    public void testOutput() {
+        final float expansion = 0.25f;
+        final int height = 120;
+
+        final CommunalHostViewPositionAlgorithm algorithm = new CommunalHostViewPositionAlgorithm();
+        algorithm.setup(expansion, height);
+        final Result result = new Result();
+        algorithm.run(result);
+
+        // Verify the communal view is shifted offscreen vertically by the correct amount.
+        assertThat((1 - expansion) * -height).isEqualTo(result.communalY);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java
new file mode 100644
index 0000000..68600de
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.settings.FakeSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.ref.WeakReference;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class CommunalSourceMonitorTest extends SysuiTestCase {
+    private CommunalSourceMonitor mCommunalSourceMonitor;
+    private FakeSettings mSecureSettings;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mSecureSettings = new FakeSettings();
+        mCommunalSourceMonitor = new CommunalSourceMonitor(
+                Handler.createAsync(TestableLooper.get(this).getLooper()), mSecureSettings);
+    }
+
+    @Test
+    public void testSourceAddedBeforeCallbackAdded() {
+        final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
+        final CommunalSource source = mock(CommunalSource.class);
+
+        mCommunalSourceMonitor.setSource(source);
+        mCommunalSourceMonitor.addCallback(callback);
+
+        verifyOnSourceAvailableCalledWith(callback, source);
+    }
+
+    @Test
+    public void testRemoveCallback() {
+        final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
+        final CommunalSource source = mock(CommunalSource.class);
+
+        mCommunalSourceMonitor.addCallback(callback);
+        mCommunalSourceMonitor.removeCallback(callback);
+        mCommunalSourceMonitor.setSource(source);
+
+        verify(callback, never()).onSourceAvailable(any());
+    }
+
+    @Test
+    public void testAddCallbackWithDefaultSetting() {
+        final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
+        final CommunalSource source = mock(CommunalSource.class);
+
+        mCommunalSourceMonitor.addCallback(callback);
+        mCommunalSourceMonitor.setSource(source);
+
+        verifyOnSourceAvailableCalledWith(callback, source);
+    }
+
+    @Test
+    public void testAddCallbackWithSettingDisabled() {
+        setCommunalEnabled(false);
+
+        final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
+        final CommunalSource source = mock(CommunalSource.class);
+
+        mCommunalSourceMonitor.addCallback(callback);
+        mCommunalSourceMonitor.setSource(source);
+
+        verify(callback, never()).onSourceAvailable(any());
+    }
+
+    @Test
+    public void testSettingEnabledAfterCallbackAdded() {
+        setCommunalEnabled(false);
+
+        final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
+        final CommunalSource source = mock(CommunalSource.class);
+
+        mCommunalSourceMonitor.addCallback(callback);
+        mCommunalSourceMonitor.setSource(source);
+
+        // The callback should not have executed since communal is disabled.
+        verify(callback, never()).onSourceAvailable(any());
+
+        // The callback should execute when the user changes the setting to enabled.
+        setCommunalEnabled(true);
+        verifyOnSourceAvailableCalledWith(callback, source);
+    }
+
+    @Test
+    public void testSettingDisabledAfterCallbackAdded() {
+        final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
+        final CommunalSource source = mock(CommunalSource.class);
+
+        mCommunalSourceMonitor.addCallback(callback);
+        mCommunalSourceMonitor.setSource(source);
+        verifyOnSourceAvailableCalledWith(callback, source);
+
+        // The callback should execute again when the setting is disabled, with a value of null.
+        setCommunalEnabled(false);
+        verify(callback).onSourceAvailable(null);
+    }
+
+    private void setCommunalEnabled(boolean enabled) {
+        mSecureSettings.putIntForUser(
+                Settings.Secure.COMMUNAL_MODE_ENABLED,
+                enabled ? 1 : 0,
+                UserHandle.USER_SYSTEM);
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    private void verifyOnSourceAvailableCalledWith(CommunalSourceMonitor.Callback callback,
+            CommunalSource source) {
+        final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
+                ArgumentCaptor.forClass(WeakReference.class);
+        verify(callback).onSourceAvailable(sourceCapture.capture());
+        assertThat(sourceCapture.getValue().get()).isEqualTo(source);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.java
new file mode 100644
index 0000000..7f85c35
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.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.systemui.communal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class CommunalStateControllerTest extends SysuiTestCase {
+    @Mock
+    private CommunalStateController.Callback mCallback;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testDefaultCommunalViewShowingState() {
+        // The state controller should report the communal view as not showing by default.
+        final CommunalStateController stateController = new CommunalStateController();
+        assertThat(stateController.getCommunalViewShowing()).isFalse();
+    }
+
+    @Test
+    public void testNotifyCommunalSurfaceShow() {
+        final CommunalStateController stateController = new CommunalStateController();
+        stateController.addCallback(mCallback);
+
+        // Verify setting communal view to showing propagates to callback.
+        stateController.setCommunalViewShowing(true);
+        verify(mCallback).onCommunalViewShowingChanged();
+        assertThat(stateController.getCommunalViewShowing()).isTrue();
+
+        clearInvocations(mCallback);
+
+        // Verify setting communal view to not showing propagates to callback.
+        stateController.setCommunalViewShowing(false);
+        verify(mCallback).onCommunalViewShowingChanged();
+        assertThat(stateController.getCommunalViewShowing()).isFalse();
+    }
+
+    @Test
+    public void testCallbackRegistration() {
+        final CommunalStateController stateController = new CommunalStateController();
+        stateController.addCallback(mCallback);
+
+        // Verify setting communal view to showing propagates to callback.
+        stateController.setCommunalViewShowing(true);
+        verify(mCallback).onCommunalViewShowingChanged();
+
+        clearInvocations(mCallback);
+
+        stateController.removeCallback(mCallback);
+        clearInvocations(mCallback);
+
+        // Verify callback not invoked after removing from state controller.
+        stateController.setCommunalViewShowing(false);
+        verify(mCallback, never()).onCommunalViewShowingChanged();
+    }
+}
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
deleted file mode 100644
index 95ab5cb..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/service/CommunalSourcePrimerTest.java
+++ /dev/null
@@ -1,223 +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.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/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index d6226aa..a32cb9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -43,6 +43,7 @@
         when(params.singleTapUsesProx()).thenReturn(true);
         when(params.longPressUsesProx()).thenReturn(true);
         when(params.getQuickPickupAodDuration()).thenReturn(500);
+        when(params.brightnessUsesProx()).thenReturn(true);
 
         doneHolder[0] = true;
         return params;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 4e8b59c..deb7d31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -29,6 +29,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -47,6 +48,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -82,6 +84,8 @@
     WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock
     DozeParameters mDozeParameters;
+    @Mock
+    DockManager mDockManager;
     private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
     private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor);
 
@@ -109,7 +113,7 @@
         mSensor = fakeSensorManager.getFakeLightSensor();
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */,
-                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager);
 
         mScreen.onScreenState(Display.STATE_ON);
     }
@@ -157,6 +161,67 @@
     }
 
     @Test
+    public void testAodDocked_doNotSelectivelyUseProx_usesLightSensor() {
+        // GIVEN the device doesn't need to selectively register for prox sensors and
+        // brightness sensor uses prox
+        when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false);
+        when(mDozeParameters.brightnessUsesProx()).thenReturn(true);
+
+        // GIVEN the device is docked and the display state changes to ON
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScreen.onScreenState(Display.STATE_ON);
+        waitForSensorManager();
+
+        // WHEN new sensor event sent
+        mSensor.sendSensorEvent(3);
+
+        // THEN brightness is updated
+        assertEquals(3, mServiceFake.screenBrightness);
+    }
+
+    @Test
+    public void testAodDocked_brightnessDoesNotUseProx_usesLightSensor() {
+        // GIVEN the device doesn't need to selectively register for prox sensors but
+        // the brightness sensor doesn't use prox
+        when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true);
+        when(mDozeParameters.brightnessUsesProx()).thenReturn(false);
+
+        // GIVEN the device is docked and the display state changes to ON
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScreen.onScreenState(Display.STATE_ON);
+        waitForSensorManager();
+
+        // WHEN new sensor event sent
+        mSensor.sendSensorEvent(3);
+
+        // THEN brightness is updated
+        assertEquals(3, mServiceFake.screenBrightness);
+    }
+
+
+    @Test
+    public void testAodDocked_noProx_brightnessUsesProx_doNotUseLightSensor() {
+        final int startBrightness = mServiceFake.screenBrightness;
+
+        // GIVEN the device needs to selectively register for prox sensors and
+        // the brightness sensor uses prox
+        when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true);
+        when(mDozeParameters.brightnessUsesProx()).thenReturn(true);
+
+        // GIVEN the device is docked and the display state is on
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScreen.onScreenState(Display.STATE_ON);
+        waitForSensorManager();
+
+        // WHEN new sensor event sent
+        mSensor.sendSensorEvent(3);
+
+        // THEN brightness is NOT changed
+        assertNotSame(3, mServiceFake.screenBrightness);
+        assertEquals(startBrightness, mServiceFake.screenBrightness);
+    }
+
+    @Test
     public void testPausingAod_doesNotResetBrightness() throws Exception {
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
@@ -175,7 +240,7 @@
     public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception {
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 Optional.empty() /* sensor */, mDozeHost, null /* handler */,
-                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager);
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE);
         reset(mDozeHost);
@@ -216,7 +281,7 @@
     public void testNullSensor() throws Exception {
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 Optional.empty() /* sensor */, mDozeHost, null /* handler */,
-                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+                mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 0c94f09..5c4c27c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -88,7 +88,7 @@
     private FakeSettings mFakeSettings = new FakeSettings();
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
-    private DozeSensors mDozeSensors;
+    private TestableDozeSensors mDozeSensors;
     private TriggerSensor mSensorTap;
 
     @Before
@@ -170,6 +170,94 @@
         assertTrue(mSensorTap.mRequested);
     }
 
+    @Test
+    public void testDozeSensorSetListening() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled */ true,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN we want to listen for the trigger sensor
+        triggerSensor.setListening(true);
+
+        // THEN the sensor is registered
+        assertTrue(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testDozeSensorSettingDisabled() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled*/ false,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN setListening is called
+        triggerSensor.setListening(true);
+
+        // THEN the sensor is not registered
+        assertFalse(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testDozeSensorIgnoreSetting() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor that's
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled*/ false,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // GIVEN sensor is listening
+        triggerSensor.setListening(true);
+
+        // WHEN ignoreSetting is called
+        triggerSensor.ignoreSetting(true);
+
+        // THEN the sensor is registered
+        assertTrue(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testUpdateListeningAfterAlreadyRegistered() {
+        // GIVEN doze sensors enabled
+        when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+        // GIVEN a trigger sensor
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                /* settingEnabled*/ true,
+                /* requiresTouchScreen */ true);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN setListening is called AND updateListening is called
+        triggerSensor.setListening(true);
+        triggerSensor.updateListening();
+
+        // THEN the sensor is still registered
+        assertTrue(triggerSensor.mRegistered);
+    }
+
     private class TestableDozeSensors extends DozeSensors {
 
         TestableDozeSensors() {
@@ -187,5 +275,17 @@
             }
             mSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap};
         }
+
+        public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled,
+                boolean requiresTouchScreen) {
+            return new TriggerSensor(/* sensor */ sensor,
+                    /* setting name */ "test_setting",
+                    /* settingDefault */ settingEnabled,
+                    /* configured */ true,
+                    /* pulseReason*/ 0,
+                    /* reportsTouchCoordinate*/ false,
+                    requiresTouchScreen,
+                    mDozeLog);
+        }
     }
 }
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/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 8c0d21e..3b1c5f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -21,6 +21,7 @@
 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.spy;
 import static org.mockito.Mockito.times;
@@ -51,6 +52,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -112,6 +114,7 @@
     @Mock private Handler mHandler;
     @Mock private UserContextProvider mUserContextProvider;
     @Mock private StatusBar mStatusBar;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private TestableLooper mTestableLooper;
 
@@ -155,7 +158,8 @@
                 mSysUiState,
                 mHandler,
                 mPackageManager,
-                Optional.of(mStatusBar)
+                Optional.of(mStatusBar),
+                mKeyguardUpdateMonitor
         );
         mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting();
 
@@ -169,14 +173,14 @@
     public void testShouldLogShow() {
         mGlobalActionsDialogLite.onShow(null);
         mTestableLooper.processAllMessages();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_POWER_MENU_OPEN);
     }
 
     @Test
     public void testShouldLogDismiss() {
         mGlobalActionsDialogLite.onDismiss(mGlobalActionsDialogLite.mDialog);
         mTestableLooper.processAllMessages();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_CLOSE);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_POWER_MENU_CLOSE);
     }
 
     @Test
@@ -186,16 +190,16 @@
         doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
         doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
         String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
         };
         doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
         GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
         dialog.onBackPressed();
         mTestableLooper.processAllMessages();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_BACK);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_BACK);
     }
 
     @Test
@@ -205,17 +209,17 @@
         doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
         doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
         String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
         };
         doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
         GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
 
         GestureDetector.SimpleOnGestureListener gestureListener = spy(dialog.mGestureListener);
         gestureListener.onSingleTapConfirmed(null);
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
     }
 
     @Test
@@ -226,10 +230,10 @@
         doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
         doReturn(true).when(mStatusBar).isKeyguardShowing();
         String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
         };
         doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
         GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
@@ -238,7 +242,7 @@
         MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
         MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0);
         gestureListener.onFling(start, end, 0, 1000);
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
         verify(mStatusBar).animateExpandSettingsPanel(null);
     }
 
@@ -250,10 +254,10 @@
         doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
         doReturn(false).when(mStatusBar).isKeyguardShowing();
         String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
         };
         doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
         GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
@@ -262,40 +266,40 @@
         MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
         MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0);
         gestureListener.onFling(start, end, 0, 1000);
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
         verify(mStatusBar).animateExpandNotificationsPanel();
     }
 
     @Test
     public void testShouldLogBugreportPress() throws InterruptedException {
-        GlobalActionsDialog.BugReportAction bugReportAction =
+        GlobalActionsDialogLite.BugReportAction bugReportAction =
                 mGlobalActionsDialogLite.makeBugReportActionForTesting();
         bugReportAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_BUGREPORT_PRESS);
     }
 
     @Test
     public void testShouldLogBugreportLongPress() {
-        GlobalActionsDialog.BugReportAction bugReportAction =
+        GlobalActionsDialogLite.BugReportAction bugReportAction =
                 mGlobalActionsDialogLite.makeBugReportActionForTesting();
         bugReportAction.onLongPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
     }
 
     @Test
     public void testShouldLogEmergencyDialerPress() {
-        GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction =
+        GlobalActionsDialogLite.EmergencyDialerAction emergencyDialerAction =
                 mGlobalActionsDialogLite.makeEmergencyDialerActionForTesting();
         emergencyDialerAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
     }
 
     @Test
     public void testShouldLogScreenshotPress() {
-        GlobalActionsDialog.ScreenshotAction screenshotAction =
+        GlobalActionsDialogLite.ScreenshotAction screenshotAction =
                 mGlobalActionsDialogLite.makeScreenshotActionForTesting();
         screenshotAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SCREENSHOT_PRESS);
     }
 
     @Test
@@ -304,7 +308,7 @@
                 com.android.internal.R.integer.config_navBarInteractionMode,
                 WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON);
 
-        GlobalActionsDialog.ScreenshotAction screenshotAction =
+        GlobalActionsDialogLite.ScreenshotAction screenshotAction =
                 mGlobalActionsDialogLite.makeScreenshotActionForTesting();
         assertThat(screenshotAction.shouldShow()).isTrue();
     }
@@ -315,12 +319,12 @@
                 com.android.internal.R.integer.config_navBarInteractionMode,
                 WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON);
 
-        GlobalActionsDialog.ScreenshotAction screenshotAction =
+        GlobalActionsDialogLite.ScreenshotAction screenshotAction =
                 mGlobalActionsDialogLite.makeScreenshotActionForTesting();
         assertThat(screenshotAction.shouldShow()).isFalse();
     }
 
-    private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) {
+    private void verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent event) {
         mTestableLooper.processAllMessages();
         verify(mUiEventLogger, times(1))
                 .log(event);
@@ -341,19 +345,19 @@
         doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
         doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
         String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
         };
         doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
         mGlobalActionsDialogLite.createActionItems();
 
         assertItemsOfType(mGlobalActionsDialogLite.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.LockDownAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
+                GlobalActionsDialogLite.EmergencyAction.class,
+                GlobalActionsDialogLite.LockDownAction.class,
+                GlobalActionsDialogLite.ShutDownAction.class,
+                GlobalActionsDialogLite.RestartAction.class);
         assertThat(mGlobalActionsDialogLite.mOverflowItems).isEmpty();
         assertThat(mGlobalActionsDialogLite.mPowerItems).isEmpty();
     }
@@ -365,19 +369,19 @@
         // make sure lockdown action will NOT be shown
         doReturn(false).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
         String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
                 // lockdown action not allowed
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
         };
         doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
         mGlobalActionsDialogLite.createActionItems();
 
         assertItemsOfType(mGlobalActionsDialogLite.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
+                GlobalActionsDialogLite.EmergencyAction.class,
+                GlobalActionsDialogLite.ShutDownAction.class,
+                GlobalActionsDialogLite.RestartAction.class);
         assertThat(mGlobalActionsDialogLite.mOverflowItems).isEmpty();
         assertThat(mGlobalActionsDialogLite.mPowerItems).isEmpty();
     }
@@ -387,7 +391,7 @@
         GlobalActionsDialogLite.LockDownAction lockDownAction =
                 mGlobalActionsDialogLite.new LockDownAction();
         lockDownAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_LOCKDOWN_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_LOCKDOWN_PRESS);
     }
 
     @Test
@@ -395,7 +399,7 @@
         GlobalActionsDialogLite.ShutDownAction shutDownAction =
                 mGlobalActionsDialogLite.new ShutDownAction();
         shutDownAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SHUTDOWN_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SHUTDOWN_PRESS);
     }
 
     @Test
@@ -403,7 +407,7 @@
         GlobalActionsDialogLite.ShutDownAction shutDownAction =
                 mGlobalActionsDialogLite.new ShutDownAction();
         shutDownAction.onLongPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
     }
 
     @Test
@@ -411,7 +415,7 @@
         GlobalActionsDialogLite.RestartAction restartAction =
                 mGlobalActionsDialogLite.new RestartAction();
         restartAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_REBOOT_PRESS);
     }
 
     @Test
@@ -419,6 +423,33 @@
         GlobalActionsDialogLite.RestartAction restartAction =
                 mGlobalActionsDialogLite.new RestartAction();
         restartAction.onLongPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
+        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
+    }
+
+    @Test
+    public void testOnLockScreen_disableSmartLock() {
+        mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+        int user = KeyguardUpdateMonitor.getCurrentUser();
+        doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+        doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+        doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+        doReturn(false).when(mStatusBar).isKeyguardShowing();
+        String[] actions = {
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+
+        // When entering power menu from lockscreen, with smart lock enabled
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+        mGlobalActionsDialogLite.showOrHideDialog(true, true);
+
+        // Then smart lock will be disabled
+        verify(mLockPatternUtils).requireCredentialEntry(eq(user));
+
+        // hide dialog again
+        mGlobalActionsDialogLite.showOrHideDialog(true, true);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
deleted file mode 100644
index 6d1db37..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.globalactions;
-
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doAnswer;
-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.app.IActivityManager;
-import android.app.admin.DevicePolicyManager;
-import android.app.trust.TrustManager;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.media.AudioManager;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.service.dreams.IDreamManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.IWindowManager;
-import android.view.View;
-import android.view.WindowManagerPolicyConstants;
-import android.widget.FrameLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.GlobalActions;
-import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.telephony.TelephonyListenerManager;
-import com.android.systemui.util.RingerModeLiveData;
-import com.android.systemui.util.RingerModeTracker;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.settings.SecureSettings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.Executor;
-import java.util.regex.Pattern;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class GlobalActionsDialogTest extends SysuiTestCase {
-    private static final long UI_TIMEOUT_MILLIS = 5000; // 5 sec
-    private static final Pattern CANCEL_BUTTON =
-            Pattern.compile("cancel", Pattern.CASE_INSENSITIVE);
-
-    private GlobalActionsDialog mGlobalActionsDialog;
-
-    @Mock private GlobalActions.GlobalActionsManager mWindowManagerFuncs;
-    @Mock private AudioManager mAudioManager;
-    @Mock private IDreamManager mDreamManager;
-    @Mock private DevicePolicyManager mDevicePolicyManager;
-    @Mock private LockPatternUtils mLockPatternUtils;
-    @Mock private BroadcastDispatcher mBroadcastDispatcher;
-    @Mock private TelephonyListenerManager mTelephonyListenerManager;
-    @Mock private GlobalSettings mGlobalSettings;
-    @Mock private Resources mResources;
-    @Mock private ConfigurationController mConfigurationController;
-    @Mock private ActivityStarter mActivityStarter;
-    @Mock private KeyguardStateController mKeyguardStateController;
-    @Mock private UserManager mUserManager;
-    @Mock private TrustManager mTrustManager;
-    @Mock private IActivityManager mActivityManager;
-    @Mock private MetricsLogger mMetricsLogger;
-    @Mock private SysuiColorExtractor mColorExtractor;
-    @Mock private IStatusBarService mStatusBarService;
-    @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
-    @Mock private IWindowManager mWindowManager;
-    @Mock private Executor mBackgroundExecutor;
-    @Mock private UiEventLogger mUiEventLogger;
-    @Mock private RingerModeTracker mRingerModeTracker;
-    @Mock private RingerModeLiveData mRingerModeLiveData;
-    @Mock private SysUiState mSysUiState;
-    @Mock GlobalActionsPanelPlugin mWalletPlugin;
-    @Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
-    @Mock private Handler mHandler;
-    @Mock private UserTracker mUserTracker;
-    @Mock private PackageManager mPackageManager;
-    @Mock private SecureSettings mSecureSettings;
-    @Mock private StatusBar mStatusBar;
-
-    private TestableLooper mTestableLooper;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mTestableLooper = TestableLooper.get(this);
-        allowTestableLooperAsMainThread();
-
-        when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
-        when(mResources.getConfiguration()).thenReturn(
-                getContext().getResources().getConfiguration());
-
-        mGlobalActionsDialog = new GlobalActionsDialog(mContext,
-                mWindowManagerFuncs,
-                mAudioManager,
-                mDreamManager,
-                mDevicePolicyManager,
-                mLockPatternUtils,
-                mBroadcastDispatcher,
-                mTelephonyListenerManager,
-                mGlobalSettings,
-                mSecureSettings,
-                null,
-                mResources,
-                mConfigurationController,
-                mActivityStarter,
-                mKeyguardStateController,
-                mUserManager,
-                mTrustManager,
-                mActivityManager,
-                null,
-                mMetricsLogger,
-                mColorExtractor,
-                mStatusBarService,
-                mNotificationShadeWindowController,
-                mWindowManager,
-                mBackgroundExecutor,
-                mUiEventLogger,
-                mRingerModeTracker,
-                mSysUiState,
-                mHandler,
-                mPackageManager,
-                Optional.of(mStatusBar)
-        );
-        mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
-
-        ColorExtractor.GradientColors backdropColors = new ColorExtractor.GradientColors();
-        backdropColors.setMainColor(Color.BLACK);
-        when(mColorExtractor.getNeutralColors()).thenReturn(backdropColors);
-        when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
-    }
-
-    @Test
-    public void testShouldLogShow() {
-        mGlobalActionsDialog.onShow(null);
-        mTestableLooper.processAllMessages();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN);
-    }
-
-    @Test
-    public void testShouldLogDismiss() {
-        mGlobalActionsDialog.onDismiss(mGlobalActionsDialog.mDialog);
-        mTestableLooper.processAllMessages();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_CLOSE);
-    }
-
-    @Test
-    public void testShouldLogBugreportPress() throws InterruptedException {
-        GlobalActionsDialog.BugReportAction bugReportAction =
-                mGlobalActionsDialog.makeBugReportActionForTesting();
-        bugReportAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS);
-    }
-
-    @Test
-    public void testShouldLogBugreportLongPress() {
-        GlobalActionsDialog.BugReportAction bugReportAction =
-                mGlobalActionsDialog.makeBugReportActionForTesting();
-        bugReportAction.onLongPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
-    }
-
-    @Test
-    public void testShouldLogEmergencyDialerPress() {
-        GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction =
-                mGlobalActionsDialog.makeEmergencyDialerActionForTesting();
-        emergencyDialerAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
-    }
-
-    @Test
-    public void testShouldLogScreenshotPress() {
-        GlobalActionsDialog.ScreenshotAction screenshotAction =
-                mGlobalActionsDialog.makeScreenshotActionForTesting();
-        screenshotAction.onPress();
-        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS);
-    }
-
-    @Test
-    public void testShouldShowScreenshot() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.integer.config_navBarInteractionMode,
-                WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON);
-
-        GlobalActionsDialog.ScreenshotAction screenshotAction =
-                mGlobalActionsDialog.makeScreenshotActionForTesting();
-        assertThat(screenshotAction.shouldShow()).isTrue();
-    }
-
-    @Test
-    public void testShouldNotShowScreenshot() {
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.integer.config_navBarInteractionMode,
-                WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON);
-
-        GlobalActionsDialog.ScreenshotAction screenshotAction =
-                mGlobalActionsDialog.makeScreenshotActionForTesting();
-        assertThat(screenshotAction.shouldShow()).isFalse();
-    }
-
-    private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) {
-        mTestableLooper.processAllMessages();
-        verify(mUiEventLogger, times(1))
-                .log(event);
-    }
-
-    @SafeVarargs
-    private static <T> void assertItemsOfType(List<T> stuff, Class<? extends T>... classes) {
-        assertThat(stuff).hasSize(classes.length);
-        for (int i = 0; i < stuff.size(); i++) {
-            assertThat(stuff.get(i)).isInstanceOf(classes[i]);
-        }
-    }
-
-    @Test
-    public void testCreateActionItems_maxThree_noOverflow() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow 3 items to be shown
-        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // ensure items are not blocked by keyguard or device provisioning
-        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
-        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
-        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
-    }
-
-    @Test
-    public void testCreateActionItems_maxThree_condensePower() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow 3 items to be shown
-        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // ensure items are not blocked by keyguard or device provisioning
-        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
-        // make sure lockdown action will be shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.LockDownAction.class,
-                GlobalActionsDialog.PowerOptionsAction.class);
-        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
-        assertItemsOfType(mGlobalActionsDialog.mPowerItems,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
-    }
-
-    @Test
-    public void testCreateActionItems_maxThree_condensePower_splitPower() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow 3 items to be shown
-        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // make sure lockdown action will be shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
-        // make sure bugreport also shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any());
-        // ensure items are not blocked by keyguard or device provisioning
-        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.LockDownAction.class,
-                GlobalActionsDialog.PowerOptionsAction.class);
-        assertItemsOfType(mGlobalActionsDialog.mOverflowItems,
-                GlobalActionsDialog.BugReportAction.class);
-        assertItemsOfType(mGlobalActionsDialog.mPowerItems,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
-    }
-
-    @Test
-    public void testCreateActionItems_maxFour_condensePower() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow 3 items to be shown
-        doReturn(4).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // make sure lockdown action will be shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
-        // ensure items are not blocked by keyguard or device provisioning
-        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.LockDownAction.class,
-                GlobalActionsDialog.PowerOptionsAction.class,
-                GlobalActionsDialog.ScreenshotAction.class);
-        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
-        assertItemsOfType(mGlobalActionsDialog.mPowerItems,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
-    }
-
-    @Test
-    public void testCreateActionItems_maxThree_doNotCondensePower() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow 3 items to be shown
-        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // make sure lockdown action will be shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
-        // make sure bugreport is also shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any());
-        // ensure items are not blocked by keyguard or device provisioning
-        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.BugReportAction.class);
-        assertItemsOfType(mGlobalActionsDialog.mOverflowItems,
-                GlobalActionsDialog.LockDownAction.class);
-        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
-    }
-
-    @Test
-    public void testCreateActionItems_maxAny() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow any number of power menu items to be shown
-        doReturn(Integer.MAX_VALUE).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // ensure items are not blocked by keyguard or device provisioning
-        doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
-        // make sure lockdown action will be shown
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class,
-                GlobalActionsDialog.LockDownAction.class);
-        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
-        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
-    }
-
-    @Test
-    public void testCreateActionItems_maxThree_lockdownDisabled_doesNotShowLockdown() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow only 3 items to be shown
-        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        // make sure lockdown action will NOT be shown
-        doReturn(false).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                // lockdown action not allowed
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
-        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
-        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
-    }
-
-    @Test
-    public void testCreateActionItems_shouldShowAction_excludeBugReport() {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        // allow only 3 items to be shown
-        doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
-        doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any());
-        // exclude bugreport in shouldShowAction to demonstrate how any button can be removed
-        doAnswer(
-                invocation -> !(invocation.getArgument(0)
-                        instanceof GlobalActionsDialog.BugReportAction))
-                .when(mGlobalActionsDialog).shouldShowAction(any());
-
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                // bugreport action not allowed
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-        mGlobalActionsDialog.createActionItems();
-
-        assertItemsOfType(mGlobalActionsDialog.mItems,
-                GlobalActionsDialog.EmergencyAction.class,
-                GlobalActionsDialog.ShutDownAction.class,
-                GlobalActionsDialog.RestartAction.class);
-        assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty();
-        assertThat(mGlobalActionsDialog.mPowerItems).isEmpty();
-    }
-
-    @Test
-    public void testShouldShowLockScreenMessage() throws RemoteException {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        mGlobalActionsDialog.mDialog = null;
-        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
-        when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
-        when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
-        mGlobalActionsDialog.mShowLockScreenCards = false;
-        setupDefaultActions();
-        when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
-        when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
-
-        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
-
-        GlobalActionsDialog.ActionsDialog dialog =
-                (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog;
-        assertThat(dialog).isNotNull();
-        assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.VISIBLE);
-
-        // Dismiss the dialog so that it does not pollute other tests
-        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
-    }
-
-    @Test
-    public void testShouldNotShowLockScreenMessage_whenWalletShownOnLockScreen()
-            throws RemoteException {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        mGlobalActionsDialog.mDialog = null;
-        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
-        when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
-        when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
-        mGlobalActionsDialog.mShowLockScreenCards = true;
-        setupDefaultActions();
-        when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
-        when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext));
-
-        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
-
-        GlobalActionsDialog.ActionsDialog dialog =
-                (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog;
-        assertThat(dialog).isNotNull();
-        assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
-
-        // Dismiss the dialog so that it does not pollute other tests
-        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
-    }
-
-    @Test
-    public void testShouldNotShowLockScreenMessage_whenWalletBothDisabled()
-            throws RemoteException {
-        mGlobalActionsDialog = spy(mGlobalActionsDialog);
-        mGlobalActionsDialog.mDialog = null;
-        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
-
-        when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo());
-        when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED);
-        mGlobalActionsDialog.mShowLockScreenCards = true;
-        setupDefaultActions();
-        when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController);
-        when(mWalletController.getPanelContent()).thenReturn(null);
-
-        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
-
-        GlobalActionsDialog.ActionsDialog dialog =
-                (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog;
-        assertThat(dialog).isNotNull();
-        assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
-
-        // Dismiss the dialog so that it does not pollute other tests
-        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
-    }
-
-    private UserInfo newUserInfo() {
-        return new UserInfo(0, null, null, UserInfo.FLAG_PRIMARY, null);
-    }
-
-    private void setupDefaultActions() {
-        String[] actions = {
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
-                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
-        };
-        doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/idle/IdleHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/idle/IdleHostViewControllerTest.java
new file mode 100644
index 0000000..a685e20
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/idle/IdleHostViewControllerTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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 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.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.testing.AndroidTestingRunner;
+import android.view.Choreographer;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.InputChannelCompat;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+
+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.time.Instant;
+
+import javax.inject.Provider;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class IdleHostViewControllerTest extends SysuiTestCase {
+    @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private PowerManager mPowerManager;
+    @Mock private AsyncSensorManager mSensorManager;
+    @Mock private IdleHostView mIdleHostView;
+    @Mock private InputMonitorFactory mInputMonitorFactory;
+    @Mock private DelayableExecutor mDelayableExecutor;
+    @Mock private Resources mResources;
+    @Mock private Looper mLooper;
+    @Mock private Provider<View> mViewProvider;
+    @Mock private Choreographer mChoreographer;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private Sensor mSensor;
+    @Mock private DreamHelper mDreamHelper;
+    @Mock private InputMonitorCompat mInputMonitor;
+    @Mock private InputChannelCompat.InputEventReceiver mInputEventReceiver;
+
+    private final long mTimestamp = Instant.now().toEpochMilli();
+    private KeyguardStateController.Callback mKeyguardStateCallback;
+    private StatusBarStateController.StateListener mStatusBarStateListener;
+    private IdleHostViewController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mResources.getBoolean(R.bool.config_enableIdleMode)).thenReturn(true);
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mSensor);
+        when(mInputMonitorFactory.getInputMonitor("IdleHostViewController"))
+                .thenReturn(mInputMonitor);
+        when(mInputMonitor.getInputReceiver(any(), any(), any())).thenReturn(mInputEventReceiver);
+
+        mController = new IdleHostViewController(mContext,
+                mBroadcastDispatcher, mPowerManager, mSensorManager, mIdleHostView,
+                mInputMonitorFactory, mDelayableExecutor, mResources, mLooper, mViewProvider,
+                mChoreographer, mKeyguardStateController, mStatusBarStateController, mDreamHelper);
+        mController.init();
+        mController.onViewAttached();
+
+        // Captures keyguard state controller callback.
+        ArgumentCaptor<KeyguardStateController.Callback> keyguardStateCallbackCaptor =
+                ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+        verify(mKeyguardStateController).addCallback(keyguardStateCallbackCaptor.capture());
+        mKeyguardStateCallback = keyguardStateCallbackCaptor.getValue();
+
+        // Captures status bar state listener.
+        ArgumentCaptor<StatusBarStateController.StateListener> statusBarStateListenerCaptor =
+                ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+        verify(mStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture());
+        mStatusBarStateListener = statusBarStateListenerCaptor.getValue();
+    }
+
+    @Test
+    public void testTimeoutToIdleMode() {
+        // Keyguard showing.
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        mKeyguardStateCallback.onKeyguardShowingChanged();
+
+        // Regular ambient lighting.
+        final SensorEvent sensorEvent = new SensorEvent(mSensor, 3, mTimestamp,
+                new float[]{90});
+        mController.onSensorChanged(sensorEvent);
+
+        // Times out.
+        ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
+        verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
+        callbackCapture.getValue().run();
+
+        // Verifies start dreaming (idle mode).
+        verify(mDreamHelper).startDreaming(any());
+    }
+
+    @Test
+    public void testTimeoutToLowLightMode() {
+        // Keyguard showing.
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        mKeyguardStateCallback.onKeyguardShowingChanged();
+
+        // Captures dream broadcast receiver;
+        ArgumentCaptor<BroadcastReceiver> dreamBroadcastReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mBroadcastDispatcher)
+                .registerReceiver(dreamBroadcastReceiverCaptor.capture(), any());
+        final BroadcastReceiver dreamBroadcastReceiver = dreamBroadcastReceiverCaptor.getValue();
+
+        // Low ambient lighting.
+        final SensorEvent sensorEvent = new SensorEvent(mSensor, 3, mTimestamp,
+                new float[]{5});
+        mController.onSensorChanged(sensorEvent);
+
+        // Verifies it goes to sleep because of low light.
+        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+
+        mStatusBarStateListener.onDozingChanged(true /*isDozing*/);
+        dreamBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STARTED));
+
+        // User wakes up the device.
+        mStatusBarStateListener.onDozingChanged(false /*isDozing*/);
+        dreamBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
+
+        // Clears power manager invocations to make sure the below dozing was triggered by the
+        // timeout.
+        clearInvocations(mPowerManager);
+
+        // Times out.
+        ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
+        verify(mDelayableExecutor, atLeastOnce()).executeDelayed(callbackCapture.capture(),
+                anyLong());
+        callbackCapture.getValue().run();
+
+        // Verifies go to sleep (low light mode).
+        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testTransitionBetweenIdleAndLowLightMode() {
+        // Regular ambient lighting.
+        final SensorEvent sensorEventRegularLight = new SensorEvent(mSensor, 3, mTimestamp,
+                new float[]{90});
+        mController.onSensorChanged(sensorEventRegularLight);
+
+        // Keyguard showing.
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        mKeyguardStateCallback.onKeyguardShowingChanged();
+
+        // Times out.
+        ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
+        verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
+        callbackCapture.getValue().run();
+
+        // Verifies in idle mode (dreaming).
+        verify(mDreamHelper).startDreaming(any());
+        clearInvocations(mDreamHelper);
+
+        // Ambient lighting becomes dim.
+        final SensorEvent sensorEventLowLight = new SensorEvent(mSensor, 3, mTimestamp,
+                new float[]{5});
+        mController.onSensorChanged(sensorEventLowLight);
+
+        // Verifies in low light mode (dozing).
+        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+
+        // Ambient lighting becomes bright again.
+        mController.onSensorChanged(sensorEventRegularLight);
+
+        // Verifies in idle mode (dreaming).
+        verify(mDreamHelper).startDreaming(any());
+    }
+
+    @Test
+    public void testStartDozingWhenLowLight() {
+        // Regular ambient lighting.
+        final SensorEvent sensorEventRegularLight = new SensorEvent(mSensor, 3, mTimestamp,
+                new float[]{90});
+        mController.onSensorChanged(sensorEventRegularLight);
+
+        // Keyguard showing.
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        mKeyguardStateCallback.onKeyguardShowingChanged();
+
+        // Verifies it doesn't go to sleep yet.
+        verify(mPowerManager, never()).goToSleep(anyLong(), anyInt(), anyInt());
+
+        // Ambient lighting becomes dim.
+        final SensorEvent sensorEventLowLight = new SensorEvent(mSensor, 3, mTimestamp,
+                new float[]{5});
+        mController.onSensorChanged(sensorEventLowLight);
+
+        // Verifies it goes to sleep.
+        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testInputEventReceiverLifecycle() {
+        // Keyguard showing.
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        mKeyguardStateCallback.onKeyguardShowingChanged();
+
+        // Should register input event receiver.
+        verify(mInputMonitor).getInputReceiver(any(), any(), any());
+
+        // Keyguard dismissed.
+        when(mKeyguardStateController.isShowing()).thenReturn(false);
+        mKeyguardStateCallback.onKeyguardShowingChanged();
+
+        // Should dispose input event receiver.
+        verify(mInputEventReceiver).dispose();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
new file mode 100644
index 0000000..d279bbb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.keyguard;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.os.Vibrator;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.LockIconView;
+import com.android.keyguard.LockIconViewController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class LockIconViewControllerTest extends SysuiTestCase {
+    private @Mock LockIconView mLockIconView;
+    private @Mock Context mContext;
+    private @Mock Resources mResources;
+    private @Mock DisplayMetrics mDisplayMetrics;
+    private @Mock StatusBarStateController mStatusBarStateController;
+    private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private @Mock KeyguardViewController mKeyguardViewController;
+    private @Mock KeyguardStateController mKeyguardStateController;
+    private @Mock FalsingManager mFalsingManager;
+    private @Mock AuthController mAuthController;
+    private @Mock DumpManager mDumpManager;
+    private @Mock AccessibilityManager mAccessibilityManager;
+    private @Mock ConfigurationController mConfigurationController;
+    private @Mock DelayableExecutor mDelayableExecutor;
+    private @Mock Vibrator mVibrator;
+    private @Mock AuthRippleController mAuthRippleController;
+
+    private LockIconViewController mLockIconViewController;
+
+    // Capture listeners so that they can be used to send events
+    @Captor private ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
+            ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+    private View.OnAttachStateChangeListener mAttachListener;
+
+    @Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor;
+    private AuthController.Callback mAuthControllerCallback;
+
+    @Captor private ArgumentCaptor<PointF> mPointCaptor;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mLockIconView.getResources()).thenReturn(mResources);
+        when(mLockIconView.getContext()).thenReturn(mContext);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+
+        mLockIconViewController = new LockIconViewController(
+                mLockIconView,
+                mStatusBarStateController,
+                mKeyguardUpdateMonitor,
+                mKeyguardViewController,
+                mKeyguardStateController,
+                mFalsingManager,
+                mAuthController,
+                mDumpManager,
+                mAccessibilityManager,
+                mConfigurationController,
+                mDelayableExecutor,
+                mVibrator,
+                mAuthRippleController
+        );
+    }
+
+    @Test
+    public void testUpdateFingerprintLocationOnInit() {
+        // GIVEN fp sensor location is available pre-init
+        final PointF udfpsLocation = new PointF(50, 75);
+        final int radius = 33;
+        final FingerprintSensorPropertiesInternal fpProps =
+                new FingerprintSensorPropertiesInternal(
+                        /* sensorId */ 0,
+                        /* strength */ 0,
+                        /* max enrollments per user */ 5,
+                        /* component info */ new ArrayList<>(),
+                        /* sensorType */ 3,
+                        /* resetLockoutRequiresHwToken */ false,
+                        (int) udfpsLocation.x, (int) udfpsLocation.y, radius);
+        when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
+        when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+
+        // WHEN lock icon view controller is initialized and attached
+        mLockIconViewController.init();
+        captureAttachListener();
+        mAttachListener.onViewAttachedToWindow(null);
+
+        // THEN lock icon view location is updated with the same coordinates as fpProps
+        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
+        assertEquals(udfpsLocation, mPointCaptor.getValue());
+    }
+
+    @Test
+    public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() {
+        // GIVEN fp sensor location is not available pre-init
+        when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
+        when(mAuthController.getUdfpsProps()).thenReturn(null);
+        mLockIconViewController.init();
+
+        // GIVEN fp sensor location is available post-init
+        captureAuthControllerCallback();
+        final PointF udfpsLocation = new PointF(50, 75);
+        final int radius = 33;
+        final FingerprintSensorPropertiesInternal fpProps =
+                new FingerprintSensorPropertiesInternal(
+                        /* sensorId */ 0,
+                        /* strength */ 0,
+                        /* max enrollments per user */ 5,
+                        /* component info */ new ArrayList<>(),
+                        /* sensorType */ 3,
+                        /* resetLockoutRequiresHwToken */ false,
+                        (int) udfpsLocation.x, (int) udfpsLocation.y, radius);
+        when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
+        when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+
+        // WHEN all authenticators are registered
+        mAuthControllerCallback.onAllAuthenticatorsRegistered();
+
+        // THEN lock icon view location is updated with the same coordinates as fpProps
+        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
+        assertEquals(udfpsLocation, mPointCaptor.getValue());
+    }
+
+    private void captureAuthControllerCallback() {
+        verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture());
+        mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue();
+    }
+
+    private void captureAttachListener() {
+        verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture());
+        mAttachListener = mAttachCaptor.getValue();
+    }
+}
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/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index b129fdd..42629f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -37,6 +37,7 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.LiveData
 import androidx.test.filters.SmallTest
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.media.dialog.MediaOutputDialogFactory
 import com.android.systemui.plugins.ActivityStarter
@@ -101,7 +102,6 @@
     private lateinit var seamless: ViewGroup
     private lateinit var seamlessIcon: ImageView
     private lateinit var seamlessText: TextView
-    private lateinit var seamlessFallback: ImageView
     private lateinit var seekBar: SeekBar
     private lateinit var elapsedTimeView: TextView
     private lateinit var totalTimeView: TextView
@@ -154,8 +154,6 @@
         whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
         seamlessText = TextView(context)
         whenever(holder.seamlessText).thenReturn(seamlessText)
-        seamlessFallback = ImageView(context)
-        whenever(holder.seamlessFallback).thenReturn(seamlessFallback)
         seekBar = SeekBar(context)
         whenever(holder.seekBar).thenReturn(seekBar)
         elapsedTimeView = TextView(context)
@@ -239,21 +237,19 @@
     @Test
     fun bindDisabledDevice() {
         seamless.id = 1
-        seamlessFallback.id = 2
+        val fallbackString = context.getString(R.string.media_seamless_other_device)
         player.attachPlayer(holder)
         val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
                 emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, true, null)
         player.bindPlayer(state, PACKAGE)
-        verify(expandedSet).setVisibility(seamless.id, View.GONE)
-        verify(expandedSet).setVisibility(seamlessFallback.id, View.VISIBLE)
-        verify(collapsedSet).setVisibility(seamless.id, View.GONE)
-        verify(collapsedSet).setVisibility(seamlessFallback.id, View.VISIBLE)
+        assertThat(seamless.isEnabled()).isFalse()
+        assertThat(seamlessText.getText()).isEqualTo(fallbackString)
+        assertThat(seamless.contentDescription).isEqualTo(fallbackString)
     }
 
     @Test
     fun bindNullDevice() {
-        val fallbackString = context.getResources().getString(
-                com.android.internal.R.string.ext_media_seamless_action)
+        val fallbackString = context.getResources().getString(R.string.media_seamless_other_device)
         player.attachPlayer(holder)
         val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
                 emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null)
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/AutoAddTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
index de7abf8..922c6b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
@@ -14,13 +14,19 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
 import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
-import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.testing.AndroidTestingRunner;
@@ -28,13 +34,24 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+import java.util.concurrent.Executor;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -43,42 +60,38 @@
 
     private static final int USER = 0;
 
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private QSHost mQSHost;
+    @Mock
+    private DumpManager mDumpManager;
+    @Captor
+    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
+    @Captor
+    private ArgumentCaptor<IntentFilter> mIntentFilterArgumentCaptor;
+
+    private Executor mBackgroundExecutor = Runnable::run; // Direct executor
     private AutoAddTracker mAutoTracker;
+    private SecureSettings mSecureSettings;
 
     @Before
     public void setUp() {
-        Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, "");
-    }
+        MockitoAnnotations.initMocks(this);
 
-    @Test
-    public void testMigration() {
-        Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
-        Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
-        mAutoTracker = new AutoAddTracker(mContext, USER);
+        mSecureSettings = new FakeSettings();
+
+        mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, null, USER);
+
+        mAutoTracker = createAutoAddTracker(USER);
         mAutoTracker.initialize();
-
-        assertTrue(mAutoTracker.isAdded(SAVER));
-        assertTrue(mAutoTracker.isAdded(WORK));
-        assertFalse(mAutoTracker.isAdded(INVERSION));
-
-        // These keys have been removed; retrieving their values should always return the default.
-        assertTrue(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true ));
-        assertFalse(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, false));
-        assertTrue(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, true));
-        assertFalse(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, false));
-
-        mAutoTracker.destroy();
     }
 
     @Test
     public void testChangeFromBackup() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
-
         assertFalse(mAutoTracker.isAdded(SAVER));
 
-        Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, SAVER);
-        mAutoTracker.mObserver.onChange(false);
+        mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, SAVER, USER);
 
         assertTrue(mAutoTracker.isAdded(SAVER));
 
@@ -87,9 +100,6 @@
 
     @Test
     public void testSetAdded() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
-
         assertFalse(mAutoTracker.isAdded(SAVER));
         mAutoTracker.setTileAdded(SAVER);
 
@@ -100,14 +110,12 @@
 
     @Test
     public void testPersist() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
-
         assertFalse(mAutoTracker.isAdded(SAVER));
         mAutoTracker.setTileAdded(SAVER);
 
         mAutoTracker.destroy();
-        mAutoTracker = new AutoAddTracker(mContext, USER);
+        mAutoTracker = createAutoAddTracker(USER);
+        mAutoTracker.initialize();
 
         assertTrue(mAutoTracker.isAdded(SAVER));
 
@@ -116,22 +124,158 @@
 
     @Test
     public void testIndependentUsers() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
         mAutoTracker.setTileAdded(SAVER);
 
-        mAutoTracker = new AutoAddTracker(mContext, USER + 1);
+        mAutoTracker = createAutoAddTracker(USER + 1);
+        mAutoTracker.initialize();
         assertFalse(mAutoTracker.isAdded(SAVER));
     }
 
     @Test
     public void testChangeUser() {
-        mAutoTracker = new AutoAddTracker(mContext, USER);
-        mAutoTracker.initialize();
         mAutoTracker.setTileAdded(SAVER);
 
-        mAutoTracker = new AutoAddTracker(mContext, USER + 1);
+        mAutoTracker = createAutoAddTracker(USER + 1);
         mAutoTracker.changeUser(UserHandle.of(USER));
         assertTrue(mAutoTracker.isAdded(SAVER));
     }
+
+    @Test
+    public void testBroadcastReceiverRegistered() {
+        verify(mBroadcastDispatcher).registerReceiver(
+                any(), mIntentFilterArgumentCaptor.capture(), any(), eq(UserHandle.of(USER)));
+
+        assertTrue(
+                mIntentFilterArgumentCaptor.getValue().hasAction(Intent.ACTION_SETTING_RESTORED));
+    }
+
+    @Test
+    public void testBroadcastReceiverChangesWithUser() {
+        mAutoTracker.changeUser(UserHandle.of(USER + 1));
+
+        InOrder inOrder = Mockito.inOrder(mBroadcastDispatcher);
+        inOrder.verify(mBroadcastDispatcher).unregisterReceiver(any());
+        inOrder.verify(mBroadcastDispatcher)
+                .registerReceiver(any(), any(), any(), eq(UserHandle.of(USER + 1)));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesNotRemovedInSource_noAutoAddedInTarget() {
+        verify(mBroadcastDispatcher).registerReceiver(
+                mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,work,internet,cast";
+        Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, don't remove any current tiles
+        verify(mQSHost, never()).removeTiles(any());
+        assertEquals(restoredAutoAddTiles,
+                mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesRemovedInSource_noAutoAddedInTarget() {
+        verify(mBroadcastDispatcher)
+                .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,internet,cast";
+        Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, remove work tile
+        verify(mQSHost).removeTiles(List.of("work"));
+        assertEquals(restoredAutoAddTiles,
+                mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesRemovedInSource_sameAutoAddedinTarget() {
+        verify(mBroadcastDispatcher)
+                .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,internet,cast";
+        Intent restoreTilesIntent =
+                makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "work", restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, remove work tile
+        verify(mQSHost).removeTiles(List.of("work"));
+        assertEquals(restoredAutoAddTiles,
+                mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
+    }
+
+    @Test
+    public void testSettingRestoredWithTilesRemovedInSource_othersAutoAddedinTarget() {
+        verify(mBroadcastDispatcher)
+                .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+
+        // These tiles were present in the original device
+        String restoredTiles = "saver,internet,cast";
+        Intent restoreTilesIntent =
+                makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
+
+        // And these tiles have been auto-added in the original device
+        // (no auto-added before restore)
+        String restoredAutoAddTiles = "work";
+        Intent restoreAutoAddTilesIntent =
+                makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "inversion", restoredAutoAddTiles);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
+
+        // Then, remove work tile
+        verify(mQSHost).removeTiles(List.of("work"));
+
+        String setting = mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER);
+        assertEquals(2, setting.split(",").length);
+        assertTrue(setting.contains("work"));
+        assertTrue(setting.contains("inversion"));
+    }
+
+
+    private Intent makeRestoreIntent(
+            String settingName, String previousValue, String restoredValue) {
+        Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED);
+        intent.putExtra(Intent.EXTRA_SETTING_NAME, settingName);
+        intent.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, previousValue);
+        intent.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, restoredValue);
+        return intent;
+    }
+
+    private AutoAddTracker createAutoAddTracker(int user) {
+        // Null handler wil dispatch sync.
+        return new AutoAddTracker(
+                mSecureSettings,
+                mBroadcastDispatcher,
+                mQSHost,
+                mDumpManager,
+                null,
+                mBackgroundExecutor,
+                user
+        );
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
new file mode 100644
index 0000000..e54a6ec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -0,0 +1,93 @@
+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.qs.FooterActionsController.ExpansionState
+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 FooterActionsControllerTest : 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: FooterActionsController
+
+    private val metricsLogger: MetricsLogger = FakeMetricsLogger()
+    private lateinit var view: FooterActionsView
+    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.footer_actions, null) as FooterActionsView
+
+        controller = FooterActionsController(view, qsPanelController, activityStarter,
+                userManager, userInfoController, multiUserSwitchController,
+                deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
+                globalActionsDialog, uiEventLogger, showPMLiteButton = true,
+                buttonsVisibleState = ExpansionState.EXPANDED)
+        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..8b19c50 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 FooterActionsController mFooterActionsController;
 
     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, mFooterActionsController);
 
         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 109721f..1ed34d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -48,6 +48,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.dagger.QSFragmentComponent;
 import com.android.systemui.qs.external.CustomTileStatePersister;
+import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.settings.UserTracker;
@@ -95,6 +96,10 @@
     private KeyguardBypassController mBypassController;
     @Mock
     private FalsingManager mFalsingManager;
+    @Mock
+    private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
+    @Mock
+    private TileServiceRequestController mTileServiceRequestController;
 
     public QSFragmentTest() {
         super(QSFragment.class);
@@ -108,6 +113,9 @@
         when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent);
         when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController);
 
+        when(mTileServiceRequestControllerBuilder.create(any()))
+                .thenReturn(mTileServiceRequestController);
+
         mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
         mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
                 new LayoutInflaterBuilder(mContext)
@@ -136,7 +144,8 @@
                 () -> mock(AutoTileManager.class), mock(DumpManager.class),
                 mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
                 mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
-                mock(SecureSettings.class), mock(CustomTileStatePersister.class));
+                mock(SecureSettings.class), mock(CustomTileStatePersister.class),
+                mTileServiceRequestControllerBuilder);
         qs.setHost(host);
 
         qs.setListening(true);
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 3b78632..c746bca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -18,14 +18,12 @@
 
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.TestCase.assertFalse;
 
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -44,7 +42,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;
@@ -53,7 +50,6 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
@@ -61,6 +57,7 @@
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.external.CustomTileStatePersister;
 import com.android.systemui.qs.external.TileServiceKey;
+import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.settings.UserTracker;
@@ -69,17 +66,14 @@
 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.FakeSettings;
 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;
@@ -125,42 +119,34 @@
     private UiEventLogger mUiEventLogger;
     @Mock
     private UserTracker mUserTracker;
-    @Mock
     private SecureSettings mSecureSettings;
     @Mock
     private CustomTileStatePersister mCustomTileStatePersister;
+    @Mock
+    private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
+    @Mock
+    private TileServiceRequestController mTileServiceRequestController;
 
     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());
+        when(mTileServiceRequestControllerBuilder.create(any()))
+                .thenReturn(mTileServiceRequestController);
+
+        mSecureSettings = new FakeSettings();
+        mSecureSettings.putStringForUser(
+                QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false);
         mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
                 mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
                 mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
-                mSecureSettings, mCustomTileStatePersister);
+                mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder);
         setUpTileFactory();
-
-        when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
-                .thenReturn("");
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        if (mMockingSession != null) {
-            mMockingSession.finishMocking();
-        }
     }
 
     private void setUpTileFactory() {
@@ -383,6 +369,16 @@
                 .removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId()));
     }
 
+    @Test
+    public void testRemoveTiles() {
+        List<String> tiles = List.of("spec1", "spec2", "spec3");
+        mQSTileHost.saveTilesToSettings(tiles);
+
+        mQSTileHost.removeTiles(List.of("spec1", "spec2"));
+
+        assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs);
+    }
+
     private class TestQSTileHost extends QSTileHost {
         TestQSTileHost(Context context, StatusBarIconController iconController,
                 QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
@@ -390,11 +386,12 @@
                 Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
                 BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
                 UiEventLogger uiEventLogger, UserTracker userTracker,
-                SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) {
+                SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
+                TileServiceRequestController.Builder tileServiceRequestControllerBuilder) {
             super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
                     tunerService, autoTiles, dumpManager, broadcastDispatcher,
                     Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
-                    customTileStatePersister);
+                    customTileStatePersister, tileServiceRequestControllerBuilder);
         }
 
         @Override
@@ -408,14 +405,11 @@
         @Override
         void saveTilesToSettings(List<String> tileSpecs) {
             super.saveTilesToSettings(tileSpecs);
-
-            ArgumentCaptor<String> specs = ArgumentCaptor.forClass(String.class);
-            verify(mSecureSettings, atLeastOnce()).putStringForUser(eq(QSTileHost.TILES_SETTING),
-                    specs.capture(), isNull(), eq(false), anyInt(), eq(true));
-
             // After tiles are changed, make sure to call onTuningChanged with the new setting if it
             // changed
-            onTuningChanged(TILES_SETTING, specs.getValue());
+            String specs = mSecureSettings.getStringForUser(
+                    QSTileHost.TILES_SETTING, mUserTracker.getUserId());
+            onTuningChanged(TILES_SETTING, specs);
         }
     }
 
@@ -430,7 +424,7 @@
                     mock(MetricsLogger.class),
                     mock(StatusBarStateController.class),
                     mock(ActivityStarter.class),
-                    mQSLogger
+                    QSTileHostTest.this.mQSLogger
             );
         }
 
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 66a006f..59948d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs
 
+import android.content.res.Configuration
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import com.android.internal.logging.MetricsLogger
@@ -27,12 +28,13 @@
 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.flags.FeatureFlags
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.any
@@ -65,9 +67,11 @@
     @Mock
     private lateinit var tileView: QSTileView
     @Mock
-    private lateinit var featureFlags: FeatureFlags
-    @Mock
     private lateinit var quickQsBrightnessController: QuickQSBrightnessController
+    @Mock
+    private lateinit var footerActionsController: FooterActionsController
+    @Captor
+    private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
 
     private lateinit var controller: QuickQSPanelController
 
@@ -76,6 +80,7 @@
         MockitoAnnotations.initMocks(this)
 
         `when`(quickQSPanel.tileLayout).thenReturn(tileLayout)
+        `when`(quickQSPanel.isAttachedToWindow).thenReturn(true)
         `when`(quickQSPanel.dumpableTag).thenReturn("")
         `when`(quickQSPanel.resources).thenReturn(mContext.resources)
         `when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
@@ -90,7 +95,8 @@
                 uiEventLogger,
                 qsLogger,
                 dumpManager,
-                quickQsBrightnessController
+                quickQsBrightnessController,
+                footerActionsController
         )
 
         controller.init()
@@ -120,4 +126,16 @@
 
         verify(quickQSPanel, times(limit)).addTile(any())
     }
+
+    @Test
+    fun testBrightnessAndFooterVisibilityRefreshedWhenConfigurationChanged() {
+        // times(2) because both controller and base controller are registering their listeners
+        verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
+
+        captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+
+        verify(quickQsBrightnessController).refreshVisibility(anyBoolean())
+        // times(2) because footer visibility is also refreshed on controller init
+        verify(footerActionsController, times(2)).refreshVisibility(anyBoolean())
+    }
 }
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 a6d044a..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,17 +45,14 @@
 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;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
@@ -64,7 +61,6 @@
 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/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 9b5c161..97ad8bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -51,6 +51,7 @@
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
@@ -270,4 +271,22 @@
         verify(customTileStatePersister)
                 .persistState(TileServiceKey(componentName, customTile.user), t)
     }
+
+    @Test
+    fun testAvailableBeforeInitialization() {
+        `when`(packageManager.getApplicationInfo(anyString(), anyInt()))
+                .thenThrow(PackageManager.NameNotFoundException())
+        val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+        assertTrue(tile.isAvailable)
+    }
+
+    @Test
+    fun testNotAvailableAfterInitializationWithoutIcon() {
+        val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+        reset(tileHost)
+        tile.initialize()
+        testableLooper.processAllMessages()
+        assertFalse(tile.isAvailable)
+        verify(tileHost).removeTile(tile.tileSpec)
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogTest.kt
new file mode 100644
index 0000000..d49673d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.external
+
+import android.graphics.drawable.Icon
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTileView
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class TileRequestDialogTest : SysuiTestCase() {
+
+    companion object {
+        private const val APP_NAME = "App name"
+        private const val LABEL = "Label"
+    }
+
+    private lateinit var dialog: TileRequestDialog
+
+    @Before
+    fun setUp() {
+        // Create in looper so we can make sure that the tile is fully updated
+        TestableLooper.get(this).runWithLooper {
+            dialog = TileRequestDialog(mContext)
+        }
+    }
+
+    @After
+    fun teardown() {
+        if (this::dialog.isInitialized) {
+            dialog.dismiss()
+        }
+    }
+
+    @Test
+    fun useCorrectTheme() {
+        assertThat(dialog.context.themeResId).isEqualTo(R.style.TileRequestDialog)
+    }
+
+    @Test
+    fun setTileData_hasCorrectViews() {
+        val icon = Icon.createWithResource(mContext, R.drawable.cloud)
+        val tileData = TileRequestDialog.TileData(APP_NAME, LABEL, icon)
+
+        dialog.setTileData(tileData)
+        dialog.show()
+
+        val content = dialog.requireViewById<ViewGroup>(TileRequestDialog.CONTENT_ID)
+
+        assertThat(content.childCount).isEqualTo(2)
+        assertThat(content.getChildAt(0)).isInstanceOf(TextView::class.java)
+        assertThat(content.getChildAt(1)).isInstanceOf(QSTileView::class.java)
+    }
+
+    @Test
+    fun setTileData_hasCorrectAppName() {
+        val icon = Icon.createWithResource(mContext, R.drawable.cloud)
+        val tileData = TileRequestDialog.TileData(APP_NAME, LABEL, icon)
+
+        dialog.setTileData(tileData)
+        dialog.show()
+
+        val content = dialog.requireViewById<ViewGroup>(TileRequestDialog.CONTENT_ID)
+        val text = content.getChildAt(0) as TextView
+        assertThat(text.text.toString()).contains(APP_NAME)
+    }
+
+    @Test
+    fun setTileData_hasCorrectLabel() {
+        val icon = Icon.createWithResource(mContext, R.drawable.cloud)
+        val tileData = TileRequestDialog.TileData(APP_NAME, LABEL, icon)
+
+        dialog.setTileData(tileData)
+        dialog.show()
+
+        TestableLooper.get(this).processAllMessages()
+
+        val content = dialog.requireViewById<ViewGroup>(TileRequestDialog.CONTENT_ID)
+        val tile = content.getChildAt(1) as QSTileView
+        assertThat((tile.label as TextView).text.toString()).isEqualTo(LABEL)
+    }
+
+    @Test
+    fun setTileData_hasIcon() {
+        val icon = Icon.createWithResource(mContext, R.drawable.cloud)
+        val tileData = TileRequestDialog.TileData(APP_NAME, LABEL, icon)
+
+        dialog.setTileData(tileData)
+        dialog.show()
+
+        TestableLooper.get(this).processAllMessages()
+
+        val content = dialog.requireViewById<ViewGroup>(TileRequestDialog.CONTENT_ID)
+        val tile = content.getChildAt(1) as QSTileView
+        assertThat((tile.icon.iconView as ImageView).drawable).isNotNull()
+    }
+
+    @Test
+    fun setTileData_nullIcon_hasIcon() {
+        val tileData = TileRequestDialog.TileData(APP_NAME, LABEL, null)
+
+        dialog.setTileData(tileData)
+        dialog.show()
+
+        TestableLooper.get(this).processAllMessages()
+
+        val content = dialog.requireViewById<ViewGroup>(TileRequestDialog.CONTENT_ID)
+        val tile = content.getChildAt(1) as QSTileView
+        assertThat((tile.icon.iconView as ImageView).drawable).isNotNull()
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
new file mode 100644
index 0000000..ce8e58ca
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.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.external
+
+import android.content.ComponentName
+import android.content.DialogInterface
+import android.graphics.drawable.Icon
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.function.Consumer
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TileServiceRequestControllerTest : SysuiTestCase() {
+
+    companion object {
+        private val TEST_COMPONENT = ComponentName("test_pkg", "test_cls")
+        private const val TEST_APP_NAME = "App"
+        private const val TEST_LABEL = "Label"
+    }
+
+    @Mock
+    private lateinit var tileRequestDialog: TileRequestDialog
+    @Mock
+    private lateinit var qsTileHost: QSTileHost
+    @Mock
+    private lateinit var commandRegistry: CommandRegistry
+    @Mock
+    private lateinit var icon: Icon
+
+    private lateinit var controller: TileServiceRequestController
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        // Tile not present by default
+        `when`(qsTileHost.indexOf(anyString())).thenReturn(-1)
+
+        controller = TileServiceRequestController(qsTileHost, commandRegistry) {
+            tileRequestDialog
+        }
+
+        controller.init()
+    }
+
+    @Test
+    fun requestTileAdd_dataIsPassedToDialog() {
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, Callback())
+
+        verify(tileRequestDialog).setTileData(
+                TileRequestDialog.TileData(TEST_APP_NAME, TEST_LABEL, icon)
+        )
+    }
+
+    @Test
+    fun tileAlreadyAdded_correctResult() {
+        `when`(qsTileHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
+
+        val callback = Callback()
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+
+        assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.TILE_ALREADY_ADDED)
+        verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
+    }
+
+    @Test
+    fun showAllUsers_set() {
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, Callback())
+        verify(tileRequestDialog).setShowForAllUsers(true)
+    }
+
+    @Test
+    fun cancelOnTouchOutside_set() {
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, Callback())
+        verify(tileRequestDialog).setCanceledOnTouchOutside(true)
+    }
+
+    @Test
+    fun cancelListener_dismissResult() {
+        val cancelListenerCaptor =
+                ArgumentCaptor.forClass(DialogInterface.OnCancelListener::class.java)
+
+        val callback = Callback()
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+        verify(tileRequestDialog).setOnCancelListener(capture(cancelListenerCaptor))
+
+        cancelListenerCaptor.value.onCancel(tileRequestDialog)
+        assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.DISMISSED)
+        verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
+    }
+
+    @Test
+    fun positiveActionListener_tileAddedResult() {
+        val clickListenerCaptor =
+                ArgumentCaptor.forClass(DialogInterface.OnClickListener::class.java)
+
+        val callback = Callback()
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+        verify(tileRequestDialog).setPositiveButton(anyInt(), capture(clickListenerCaptor))
+
+        clickListenerCaptor.value.onClick(tileRequestDialog, DialogInterface.BUTTON_POSITIVE)
+
+        assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.ADD_TILE)
+        verify(qsTileHost).addTile(TEST_COMPONENT, /* end */ true)
+    }
+
+    @Test
+    fun negativeActionListener_tileNotAddedResult() {
+        val clickListenerCaptor =
+                ArgumentCaptor.forClass(DialogInterface.OnClickListener::class.java)
+
+        val callback = Callback()
+        controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
+        verify(tileRequestDialog).setNegativeButton(anyInt(), capture(clickListenerCaptor))
+
+        clickListenerCaptor.value.onClick(tileRequestDialog, DialogInterface.BUTTON_NEGATIVE)
+
+        assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.DONT_ADD_TILE)
+        verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
+    }
+
+    private class Callback : Consumer<Int> {
+        var lastAccepted: Int? = null
+            private set
+        override fun accept(t: Int) {
+            lastAccepted = t
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 2b18404..e027ab7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -98,12 +98,20 @@
     private UserTracker mUserTracker;
     @Mock
     private SecureSettings  mSecureSettings;
+    @Mock
+    private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
+    @Mock
+    private TileServiceRequestController mTileServiceRequestController;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(BluetoothController.class);
         mManagers = new ArrayList<>();
+
+        when(mTileServiceRequestControllerBuilder.create(any()))
+                .thenReturn(mTileServiceRequestController);
+
         QSTileHost host = new QSTileHost(mContext,
                 mStatusBarIconController,
                 mQSFactory,
@@ -119,7 +127,8 @@
                 mUiEventLogger,
                 mUserTracker,
                 mSecureSettings,
-                mock(CustomTileStatePersister.class));
+                mock(CustomTileStatePersister.class),
+                mTileServiceRequestControllerBuilder);
         mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
                 mUserTracker);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
index 63ebe92..23e5168 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -74,6 +75,24 @@
     }
 
     @Test
+    public void testMutateIconDrawable() {
+        SlashImageView iv = mock(SlashImageView.class);
+        Drawable originalDrawable = mock(Drawable.class);
+        Drawable otherDrawable = mock(Drawable.class);
+        State s = new State();
+        s.icon = mock(Icon.class);
+        when(s.icon.getInvisibleDrawable(eq(mContext))).thenReturn(originalDrawable);
+        when(s.icon.getDrawable(eq(mContext))).thenReturn(originalDrawable);
+        when(iv.isShown()).thenReturn(true);
+        when(originalDrawable.getConstantState()).thenReturn(fakeConstantState(otherDrawable));
+
+
+        mIconView.updateIcon(iv, s, /* allowAnimations= */true);
+
+        verify(iv).setState(any(), eq(otherDrawable));
+    }
+
+    @Test
     public void testNoFirstFade() {
         ImageView iv = mock(ImageView.class);
         State s = new State();
@@ -104,4 +123,18 @@
     public void testIconNotSet_toString() {
         assertFalse(mIconView.toString().contains("lastIcon"));
     }
+
+    private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) {
+        return new Drawable.ConstantState() {
+            @Override
+            public Drawable newDrawable() {
+                return otherDrawable;
+            }
+
+            @Override
+            public int getChangingConfigurations() {
+                return 1;
+            }
+        };
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index a70c2be..8922b43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -228,7 +228,9 @@
         mTile.handleClick(null /* view */);
         mTestableLooper.processAllMessages();
 
-        verify(mSpiedContext).startActivity(mIntentCaptor.capture());
+        verify(mActivityStarter).startActivity(mIntentCaptor.capture(), eq(true) /* dismissShade */,
+                (ActivityLaunchAnimator.Controller) eq(null),
+                eq(true) /* showOverLockscreenWhenLocked */);
 
         Intent nextStartedIntent = mIntentCaptor.getValue();
         String walletClassName = "com.android.systemui.wallet.ui.WalletActivity";
@@ -246,7 +248,8 @@
         mTestableLooper.processAllMessages();
 
         verify(mActivityStarter).startActivity(mIntentCaptor.capture(), eq(true) /* dismissShade */,
-                (ActivityLaunchAnimator.Controller) eq(null));
+                (ActivityLaunchAnimator.Controller) eq(null),
+                eq(true) /* showOverLockscreenWhenLocked */);
 
         Intent nextStartedIntent = mIntentCaptor.getValue();
         String walletClassName = "com.android.systemui.wallet.ui.WalletActivity";
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 9c3301e..77946cf 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,28 +2,37 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.graphics.drawable.Drawable;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableResources;
 import android.view.View;
 import android.widget.LinearLayout;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.wifitrackerlib.WifiEntry;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.util.Arrays;
+import java.util.List;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -31,58 +40,54 @@
 
     private static final String WIFI_TITLE = "Wi-Fi Title";
     private static final String WIFI_SUMMARY = "Wi-Fi Summary";
+    private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp;
+    private static final int LOCK_ICON_RES_ID = R.drawable.ic_friction_lock_closed;
 
+    @Rule
+    public MockitoRule mRule = MockitoJUnit.rule();
+
+    @Mock
+    private WifiEntry mInternetWifiEntry;
+    @Mock
+    private List<WifiEntry> mWifiEntries;
     @Mock
     private WifiEntry mWifiEntry;
     @Mock
     private InternetDialogController mInternetDialogController;
     @Mock
     private WifiUtils.InternetIconInjector mWifiIconInjector;
+    @Mock
+    private Drawable mGearIcon;
+    @Mock
+    private Drawable mLockIcon;
 
+    private TestableResources mTestableResources;
     private InternetAdapter mInternetAdapter;
     private InternetAdapter.InternetViewHolder mViewHolder;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mInternetAdapter = new InternetAdapter(mInternetDialogController);
-        mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0);
+        mTestableResources = mContext.getOrCreateTestableResources();
+        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.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
+
+        mInternetAdapter = new InternetAdapter(mInternetDialogController);
+        mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0);
+        mInternetAdapter.setWifiEntries(Arrays.asList(mWifiEntry), 1 /* wifiEntriesCount */);
         mViewHolder.mWifiIconInjector = mWifiIconInjector;
     }
 
     @Test
-    public void getItemCount_withApmOnWifiOnNoDefaultWifi_returnFour() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
+    public void getItemCount_returnWifiEntriesCount() {
+        for (int i = 0; i < InternetDialogController.MAX_WIFI_ENTRY_COUNT; i++) {
+            mInternetAdapter.setWifiEntries(mWifiEntries, i /* wifiEntriesCount */);
 
-        assertThat(mInternetAdapter.getItemCount()).isEqualTo(4);
-    }
-
-    @Test
-    public void getItemCount_withApmOnWifiOnHasDefaultWifi_returnThree() {
-        when(mWifiEntry.isDefaultNetwork()).thenReturn(true);
-        when(mInternetDialogController.getDefaultWifiEntry()).thenReturn(mWifiEntry);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-
-        assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
-    }
-
-    @Test
-    public void getItemCount_withApmOffWifiOnNoDefaultWifi_returnThree() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-
-        assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
-    }
-
-    @Test
-    public void getItemCount_withApmOffWifiOnHasDefaultWifi_returnTwo() {
-        when(mWifiEntry.isDefaultNetwork()).thenReturn(true);
-        when(mInternetDialogController.getDefaultWifiEntry()).thenReturn(mWifiEntry);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-
-        assertThat(mInternetAdapter.getItemCount()).isEqualTo(2);
+            assertThat(mInternetAdapter.getItemCount()).isEqualTo(i);
+        }
     }
 
     @Test
@@ -93,7 +98,7 @@
         assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
@@ -104,11 +109,21 @@
         assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
-    public void onBindViewHolder_bindDefaultWifiNetwork_getIconWithInternet() {
+    public void onBindViewHolder_wifiLevelUnreachable_shouldNotGetWifiIcon() {
+        reset(mWifiIconInjector);
+        when(mWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
+
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        verify(mWifiIconInjector, never()).getIcon(anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void onBindViewHolder_shouldNotShowXLevelIcon_getIconWithInternet() {
         when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(false);
 
         mInternetAdapter.onBindViewHolder(mViewHolder, 0);
@@ -117,11 +132,36 @@
     }
 
     @Test
-    public void onBindViewHolder_bindNoDefaultWifiNetwork_getIconWithNoInternet() {
+    public void onBindViewHolder_shouldShowXLevelIcon_getIconWithNoInternet() {
         when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
 
         mInternetAdapter.onBindViewHolder(mViewHolder, 0);
 
         verify(mWifiIconInjector).getIcon(eq(true) /* noInternet */, anyInt());
     }
+
+    @Test
+    public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() {
+        mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon);
+
+        mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_CONNECTED, WifiEntry.SECURITY_PSK);
+
+        assertThat(mViewHolder.mWifiEndIcon.getDrawable()).isEqualTo(mGearIcon);
+    }
+
+    @Test
+    public void viewHolderUpdateEndIcon_wifiDisconnectedAndSecurityPsk_updateLockIcon() {
+        mTestableResources.addOverride(LOCK_ICON_RES_ID, mLockIcon);
+
+        mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_DISCONNECTED, WifiEntry.SECURITY_PSK);
+
+        assertThat(mViewHolder.mWifiEndIcon.getDrawable()).isEqualTo(mLockIcon);
+    }
+
+    @Test
+    public void viewHolderUpdateEndIcon_wifiDisconnectedAndSecurityNone_hideIcon() {
+        mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_DISCONNECTED, WifiEntry.SECURITY_NONE);
+
+        assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.GONE);
+    }
 }
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 f876a43..baddacc 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
@@ -10,6 +10,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -17,8 +18,6 @@
 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;
@@ -33,13 +32,13 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.settingslib.Utils;
 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;
@@ -79,41 +78,58 @@
     @Mock
     private GlobalSettings mGlobalSettings;
     @Mock
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private KeyguardStateController mKeyguardStateController;
     @Mock
     private NetworkController.AccessPointController mAccessPointController;
     @Mock
     private WifiEntry mConnectedEntry;
     @Mock
-    private WifiInfo mWifiInfo;
+    private WifiEntry mWifiEntry1;
+    @Mock
+    private WifiEntry mWifiEntry2;
+    @Mock
+    private WifiEntry mWifiEntry3;
+    @Mock
+    private WifiEntry mWifiEntry4;
     @Mock
     private ServiceState mServiceState;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
     @Mock
     private WifiUtils.InternetIconInjector mWifiIconInjector;
+    @Mock
+    InternetDialogController.InternetDialogCallback mInternetDialogCallback;
 
     private MockInternetDialogController mInternetDialogController;
     private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+    private List<WifiEntry> mAccessPoints = new ArrayList<>();
+    private List<WifiEntry> mWifiEntries = new ArrayList<>();
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
-        when(mWifiManager.getConnectionInfo()).thenReturn(mWifiInfo);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
         when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
+        when(mConnectedEntry.hasInternetAccess()).thenReturn(true);
+        when(mWifiEntry1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        when(mWifiEntry2.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        when(mWifiEntry3.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        when(mWifiEntry4.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID});
 
         mInternetDialogController = new MockInternetDialogController(mContext,
                 mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
                 mSubscriptionManager, mTelephonyManager, mWifiManager,
                 mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
-                mKeyguardUpdateMonitor, mGlobalSettings);
+                mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController);
         mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
                 mInternetDialogController.mOnSubscriptionsChangedListener);
-        mInternetDialogController.onStart(
-                mock(InternetDialogController.InternetDialogCallback.class));
+        mInternetDialogController.onStart(mInternetDialogCallback, true);
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
         mInternetDialogController.mActivityStarter = mActivityStarter;
-        mInternetDialogController.mConnectedEntry = mConnectedEntry;
         mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
     }
 
@@ -145,43 +161,63 @@
         mInternetDialogController.setAirplaneModeEnabled(false);
         when(mWifiManager.isWifiEnabled()).thenReturn(false);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
-                getResourcesString("wifi_is_off")));
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isEqualTo(getResourcesString("wifi_is_off"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isNotEqualTo(getResourcesString("wifi_is_off"));
     }
 
     @Test
     public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
         mInternetDialogController.setAirplaneModeEnabled(false);
         when(mWifiManager.isWifiEnabled()).thenReturn(true);
-        List<ScanResult> wifiScanResults = mock(ArrayList.class);
-        doReturn(0).when(wifiScanResults).size();
-        when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(true),
-                getResourcesString("wifi_empty_list_wifi_on")));
+        assertThat(mInternetDialogController.getSubtitleText(true))
+                .isEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(true))
+                .isNotEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
     }
 
     @Test
     public void getSubtitleText_withWifiEntry_returnTapToConnect() {
+        // The preconditions WiFi Entries is already in setUp()
         mInternetDialogController.setAirplaneModeEnabled(false);
         when(mWifiManager.isWifiEnabled()).thenReturn(true);
-        List<ScanResult> wifiScanResults = mock(ArrayList.class);
-        doReturn(1).when(wifiScanResults).size();
-        when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isEqualTo(getResourcesString("tap_a_network_to_connect"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isNotEqualTo(getResourcesString("tap_a_network_to_connect"));
+    }
+
+    @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("tap_a_network_to_connect")));
+                getResourcesString("unlock_to_view_networks")));
     }
 
     @Test
     public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
         mInternetDialogController.setAirplaneModeEnabled(false);
         when(mWifiManager.isWifiEnabled()).thenReturn(true);
-        List<ScanResult> wifiScanResults = new ArrayList<>();
-        doReturn(wifiScanResults).when(mWifiManager).getScanResults();
-        when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
-        when(mSubscriptionManager.getActiveSubscriptionIdList())
-                .thenReturn(new int[] {SUB_ID});
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
 
         doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
         doReturn(mServiceState).when(mTelephonyManager).getServiceState();
@@ -195,122 +231,219 @@
     public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() {
         mInternetDialogController.setAirplaneModeEnabled(false);
         when(mWifiManager.isWifiEnabled()).thenReturn(true);
-        List<ScanResult> wifiScanResults = new ArrayList<>();
-        doReturn(wifiScanResults).when(mWifiManager).getScanResults();
-        when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
-        when(mSubscriptionManager.getActiveSubscriptionIdList())
-                .thenReturn(new int[] {SUB_ID});
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
 
         doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
         doReturn(mServiceState).when(mTelephonyManager).getServiceState();
 
         when(mTelephonyManager.isDataEnabled()).thenReturn(false);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
-                getResourcesString("non_carrier_network_unavailable")));
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isEqualTo(getResourcesString("non_carrier_network_unavailable"));
+
+        // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+        mInternetDialogController.mCanConfigWifi = false;
+
+        assertThat(mInternetDialogController.getSubtitleText(false))
+                .isNotEqualTo(getResourcesString("non_carrier_network_unavailable"));
     }
 
     @Test
-    public void getDefaultWifiEntry_connectedEntryIsNull_returnNull() {
-        mInternetDialogController.mConnectedEntry = null;
-
-        assertThat(mInternetDialogController.getDefaultWifiEntry()).isNull();
+    public void getWifiDetailsSettingsIntent_withNoKey_returnNull() {
+        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent(null)).isNull();
     }
 
     @Test
-    public void getDefaultWifiEntry_connectedEntryIsNotDefault_returnNull() {
-        when(mConnectedEntry.isDefaultNetwork()).thenReturn(false);
-
-        assertThat(mInternetDialogController.getDefaultWifiEntry()).isNull();
+    public void getWifiDetailsSettingsIntent_withKey_returnIntent() {
+        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent("test_key")).isNotNull();
     }
 
     @Test
-    public void getDefaultWifiEntry_connectedEntryIsDefault_returnConnectedEntry() {
-        // The default conditions have been set in setUp().
-        //   - The connected Wi-Fi entry with the default network condition.
-
-        assertThat(mInternetDialogController.getDefaultWifiEntry()).isEqualTo(mConnectedEntry);
-    }
-
-    @Test
-    public void getDefaultWifiTitle_withNoDefaultEntry_returnEmpty() {
-        mInternetDialogController.mConnectedEntry = null;
-
-        assertThat(mInternetDialogController.getDefaultWifiTitle()).isEmpty();
-    }
-
-    @Test
-    public void getDefaultWifiTitle_withDefaultEntry_returnTitle() {
-        when(mConnectedEntry.getTitle()).thenReturn(CONNECTED_TITLE);
-
-        assertThat(mInternetDialogController.getDefaultWifiTitle()).isEqualTo(CONNECTED_TITLE);
-    }
-
-    @Test
-    public void getDefaultWifiSummary_withNoDefaultEntry_returnEmpty() {
-        mInternetDialogController.mConnectedEntry = null;
-
-        assertThat(mInternetDialogController.getDefaultWifiSummary()).isEmpty();
-    }
-
-    @Test
-    public void getDefaultWifiSummary_withDefaultEntry_returnSummary() {
-        when(mConnectedEntry.getSummary(false)).thenReturn(CONNECTED_SUMMARY);
-
-        assertThat(mInternetDialogController.getDefaultWifiSummary()).isEqualTo(CONNECTED_SUMMARY);
-    }
-
-    @Test
-    public void getWifiDetailsSettingsIntent_withNoConnectedEntry_returnNull() {
-        mInternetDialogController.mConnectedEntry = null;
-
-        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNull();
-    }
-
-    @Test
-    public void getWifiDetailsSettingsIntent_withNoConnectedEntryKey_returnNull() {
-        when(mConnectedEntry.getKey()).thenReturn(null);
-
-        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNull();
-    }
-
-    @Test
-    public void getWifiDetailsSettingsIntent_withConnectedEntryKey_returnIntent() {
-        when(mConnectedEntry.getKey()).thenReturn("test_key");
-
-        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNotNull();
-    }
-
-    @Test
-    public void getWifiConnectedDrawable_withConnectedEntry_returnIntentIconWithColorAccent() {
+    public void getInternetWifiDrawable_withConnectedEntry_returnIntentIconWithCorrectColor() {
         final Drawable drawable = mock(Drawable.class);
         when(mWifiIconInjector.getIcon(anyBoolean(), anyInt())).thenReturn(drawable);
 
-        mInternetDialogController.getConnectedWifiDrawable(mConnectedEntry);
+        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;
+    public void getInternetWifiDrawable_withWifiLevelUnreachable_returnNull() {
+        when(mConnectedEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
 
-        mInternetDialogController.launchWifiNetworkDetailsSetting();
+        Drawable drawable = mInternetDialogController.getInternetWifiDrawable(mConnectedEntry);
+
+        assertThat(drawable).isNull();
+    }
+
+    @Test
+    public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() {
+        mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */);
 
         verify(mActivityStarter, never())
                 .postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
     }
 
     @Test
-    public void launchWifiNetworkDetailsSetting_withConnectedEntryKey_startActivity() {
-        when(mConnectedEntry.getKey()).thenReturn("test_key");
-
-        mInternetDialogController.launchWifiNetworkDetailsSetting();
+    public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() {
+        mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key");
 
         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();
+    }
+
+    @Test
+    public void onAccessPointsChanged_canNotConfigWifi_doNothing() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.mCanConfigWifi = false;
+
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        verify(mInternetDialogCallback, never()).onAccessPointsChanged(any(), any());
+    }
+
+    @Test
+    public void onAccessPointsChanged_nullAccessPoints_callbackBothNull() {
+        reset(mInternetDialogCallback);
+
+        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+        verify(mInternetDialogCallback)
+                .onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntry_callbackConnectedEntryOnly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_noConnectedEntryAndOneOther_callbackWifiEntriesOnly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mWifiEntry1);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        verify(mInternetDialogCallback)
+                .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndOneOther_callbackCorrectly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndTwoOthers_callbackCorrectly() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        mAccessPoints.add(mWifiEntry2);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        mWifiEntries.add(mWifiEntry2);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndThreeOthers_callbackCutMore() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        mAccessPoints.add(mWifiEntry2);
+        mAccessPoints.add(mWifiEntry3);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        mWifiEntries.add(mWifiEntry2);
+        mWifiEntries.add(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+
+        // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(false);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.remove(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
+    @Test
+    public void onAccessPointsChanged_oneConnectedEntryAndFourOthers_callbackCutMore() {
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(true);
+        mAccessPoints.clear();
+        mAccessPoints.add(mConnectedEntry);
+        mAccessPoints.add(mWifiEntry1);
+        mAccessPoints.add(mWifiEntry2);
+        mAccessPoints.add(mWifiEntry3);
+        mAccessPoints.add(mWifiEntry4);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.clear();
+        mWifiEntries.add(mWifiEntry1);
+        mWifiEntries.add(mWifiEntry2);
+        mWifiEntries.add(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+
+        // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
+        reset(mInternetDialogCallback);
+        mInternetDialogController.setAirplaneModeEnabled(false);
+
+        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+        mWifiEntries.remove(mWifiEntry3);
+        verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+    }
+
     private String getResourcesString(String name) {
         return mContext.getResources().getString(getResourcesId(name));
     }
@@ -331,10 +464,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 856e3a1..fa9c053 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,6 @@
 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;
@@ -24,7 +19,6 @@
 import android.testing.TestableLooper;
 import android.view.View;
 import android.widget.LinearLayout;
-import android.widget.TextView;
 
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.SmallTest;
@@ -32,7 +26,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;
@@ -44,8 +37,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 @SmallTest
@@ -53,52 +44,64 @@
 @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 List<WifiEntry> mWifiEntries;
+    @Mock
+    private InternetAdapter mInternetAdapter;
+    @Mock
+    private InternetDialogController mInternetDialogController;
+
+    private InternetDialog mInternetDialog;
+    private View mDialogView;
+    private View mSubTitle;
+    private LinearLayout mMobileDataToggle;
+    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);
+        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(mWifiEntries.size()).thenReturn(1);
+
+        when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE);
+        when(mInternetDialogController.getMobileNetworkSummary())
+                .thenReturn(MOBILE_NETWORK_SUMMARY);
+        when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager);
+
+        mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
+                mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler);
+        mInternetDialog.mAdapter = mInternetAdapter;
+        mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry);
         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);
-        when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
-        when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
-        when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
+
+        mDialogView = mInternetDialog.mDialogView;
+        mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+        mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout);
+        mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+        mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
+        mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
+        mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
     }
 
     @After
@@ -107,76 +110,120 @@
     }
 
     @Test
+    public void hideWifiViews_WifiViewsGone() {
+        mInternetDialog.hideWifiViews();
+
+        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
     public void updateDialog_withApmOn_internetDialogSubTitleGone() {
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialog.updateDialog();
-        final TextView view = mInternetDialog.mDialogView.requireViewById(
-                R.id.internet_dialog_subtitle);
 
-        assertThat(view.getVisibility()).isEqualTo(View.GONE);
+        mInternetDialog.updateDialog();
+
+        assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
     public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        mInternetDialog.updateDialog();
-        final TextView view = mInternetDialog.mDialogView.requireViewById(
-                R.id.internet_dialog_subtitle);
 
-        assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
+        mInternetDialog.updateDialog();
+
+        assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
     public void updateDialog_withApmOn_mobileDataLayoutGone() {
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialog.updateDialog();
-        final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
-                R.id.mobile_network_layout);
 
-        assertThat(linearLayout.getVisibility()).isEqualTo(View.GONE);
+        mInternetDialog.updateDialog();
+
+        assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE);
     }
 
     @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(mWifiEntry.isDefaultNetwork()).thenReturn(true);
-        mInternetDialog.mConnectedWifiEntry = mWifiEntry;
 
         mInternetDialog.updateDialog();
 
-        final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
-                R.id.wifi_connected_layout);
-        assertThat(linearLayout.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
-    public void updateDialog_withWifiOnAndNoConnectedWifi_connectedWifiLayoutGone() {
+    public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/);
         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() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry);
 
-        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();
     }
@@ -184,7 +231,18 @@
     @Test
     public void showProgressBar_wifiDisabled_hideProgressBar() {
         Mockito.reset(mHandler);
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(false);
+        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();
 
@@ -195,10 +253,7 @@
     @Test
     public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
         Mockito.reset(mHandler);
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
-        List<ScanResult> wifiScanResults = mock(ArrayList.class);
-        when(wifiScanResults.size()).thenReturn(1);
-        when(mMockWifiManager.getScanResults()).thenReturn(wifiScanResults);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
 
         mInternetDialog.showProgressBar();
 
@@ -215,12 +270,10 @@
     }
 
     @Test
-    public void showProgressBar_wifiEnabledWithoutWifiScanResults_showProgressBarThenHideSearch() {
+    public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
         Mockito.reset(mHandler);
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
-        List<ScanResult> wifiScanResults = mock(ArrayList.class);
-        when(wifiScanResults.size()).thenReturn(0);
-        when(mMockWifiManager.getScanResults()).thenReturn(wifiScanResults);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry*/);
 
         mInternetDialog.showProgressBar();
 
@@ -236,78 +289,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/qs/user/UserDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt
new file mode 100644
index 0000000..d5fe588
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.user
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class UserDialogTest : SysuiTestCase() {
+
+    private lateinit var dialog: UserDialog
+
+    @Before
+    fun setUp() {
+        dialog = UserDialog(mContext)
+    }
+
+    @After
+    fun tearDown() {
+        dialog.dismiss()
+    }
+
+    @Test
+    fun doneButtonExists() {
+        assertThat(dialog.doneButton).isInstanceOf(View::class.java)
+    }
+
+    @Test
+    fun settingsButtonExists() {
+        assertThat(dialog.settingsButton).isInstanceOf(View::class.java)
+    }
+
+    @Test
+    fun gridExistsAndIsViewGroup() {
+        assertThat(dialog.grid).isInstanceOf(ViewGroup::class.java)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
new file mode 100644
index 0000000..a1760a7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
@@ -0,0 +1,203 @@
+/*
+ * 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.user
+
+import android.content.Intent
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.PseudoGridView
+import com.android.systemui.qs.tiles.UserDetailView
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatcher
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.argThat
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.function.Consumer
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class UserSwitchDialogControllerTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var dialog: UserDialog
+    @Mock
+    private lateinit var falsingManager: FalsingManager
+    @Mock
+    private lateinit var settingsView: View
+    @Mock
+    private lateinit var doneView: View
+    @Mock
+    private lateinit var activityStarter: ActivityStarter
+    @Mock
+    private lateinit var userDetailViewAdapter: UserDetailView.Adapter
+    @Mock
+    private lateinit var launchView: View
+    @Mock
+    private lateinit var gridView: PseudoGridView
+    @Captor
+    private lateinit var clickCaptor: ArgumentCaptor<View.OnClickListener>
+
+    private lateinit var controller: UserSwitchDialogController
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        `when`(dialog.settingsButton).thenReturn(settingsView)
+        `when`(dialog.doneButton).thenReturn(doneView)
+        `when`(dialog.grid).thenReturn(gridView)
+
+        `when`(launchView.context).thenReturn(mContext)
+
+        controller = UserSwitchDialogController(
+                { userDetailViewAdapter },
+                activityStarter,
+                falsingManager,
+                { dialog }
+        )
+    }
+
+    @Test
+    fun showDialog_callsDialogShow() {
+        controller.showDialog(launchView)
+        verify(dialog).show()
+    }
+
+    @Test
+    fun createCalledBeforeDoneButton() {
+        controller.showDialog(launchView)
+        val inOrder = inOrder(dialog)
+        inOrder.verify(dialog).create()
+        inOrder.verify(dialog).doneButton
+    }
+
+    @Test
+    fun createCalledBeforeSettingsButton() {
+        controller.showDialog(launchView)
+        val inOrder = inOrder(dialog)
+        inOrder.verify(dialog).create()
+        inOrder.verify(dialog).settingsButton
+    }
+
+    @Test
+    fun createCalledBeforeGrid() {
+        controller.showDialog(launchView)
+        val inOrder = inOrder(dialog)
+        inOrder.verify(dialog).create()
+        inOrder.verify(dialog).grid
+    }
+
+    @Test
+    fun dialog_showForAllUsers() {
+        controller.showDialog(launchView)
+        verify(dialog).setShowForAllUsers(true)
+    }
+
+    @Test
+    fun dialog_cancelOnTouchOutside() {
+        controller.showDialog(launchView)
+        verify(dialog).setCanceledOnTouchOutside(true)
+    }
+
+    @Test
+    fun adapterAndGridLinked() {
+        controller.showDialog(launchView)
+        verify(userDetailViewAdapter).linkToViewGroup(gridView)
+    }
+
+    @Test
+    fun clickDoneButton_dismiss() {
+        controller.showDialog(launchView)
+
+        verify(doneView).setOnClickListener(capture(clickCaptor))
+
+        clickCaptor.value.onClick(doneView)
+
+        verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
+        verify(dialog).dismiss()
+    }
+
+    @Test
+    fun clickSettingsButton_noFalsing_opensSettingsAndDismisses() {
+        `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false)
+
+        controller.showDialog(launchView)
+
+        verify(settingsView).setOnClickListener(capture(clickCaptor))
+
+        clickCaptor.value.onClick(settingsView)
+
+        verify(activityStarter)
+                .postStartActivityDismissingKeyguard(
+                        argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)),
+                        eq(0)
+                )
+        verify(dialog).dismiss()
+    }
+
+    @Test
+    fun clickSettingsButton_Falsing_notOpensSettingsAndDismisses() {
+        `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true)
+
+        controller.showDialog(launchView)
+
+        verify(settingsView).setOnClickListener(capture(clickCaptor))
+
+        clickCaptor.value.onClick(settingsView)
+
+        verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
+        verify(dialog).dismiss()
+    }
+
+    @Test
+    fun callbackFromDetailView_dismissesDialog() {
+        val captor = argumentCaptor<Consumer<UserSwitcherController.UserRecord>>()
+
+        controller.showDialog(launchView)
+        verify(userDetailViewAdapter).injectCallback(capture(captor))
+
+        captor.value.accept(mock(UserSwitcherController.UserRecord::class.java))
+
+        verify(dialog).dismiss()
+    }
+
+    private class IntentMatcher(private val action: String) : ArgumentMatcher<Intent> {
+        override fun matches(argument: Intent?): Boolean {
+            return argument?.action == action
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
index 10c878a..6f081c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
@@ -34,6 +34,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
 
@@ -274,7 +275,8 @@
             when(client.start(/* response */ any(), /* maxPages */ anyFloat()))
                     .thenReturn(immediateFuture(session));
             return new ScrollCaptureController(context, context.getMainExecutor(),
-                    client, new ImageTileSet(context.getMainThreadHandler()));
+                    client, new ImageTileSet(context.getMainThreadHandler()),
+                    new UiEventLoggerFake());
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
new file mode 100644
index 0000000..a9c6a53
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.systemui.shared.animation
+
+import android.graphics.Point
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.Surface.ROTATION_0
+import android.view.Surface.ROTATION_90
+import android.view.View
+import android.view.WindowManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var windowManager: WindowManager
+
+    @get:Rule
+    val mockito = MockitoJUnit.rule()
+
+    private lateinit var animator: UnfoldMoveFromCenterAnimator
+
+    @Before
+    fun before() {
+        animator = UnfoldMoveFromCenterAnimator(windowManager)
+    }
+
+    @Test
+    fun testRegisterViewOnTheLeftOfVerticalFold_halfProgress_viewTranslatedToTheRight() {
+        givenScreen(width = 100, height = 100, rotation = ROTATION_0)
+        val view = createView(x = 20)
+        animator.registerViewForAnimation(view)
+        animator.onTransitionStarted()
+
+        animator.onTransitionProgress(0.5f)
+
+        // Positive translationX -> translated to the right
+        assertThat(view.translationX).isWithin(0.1f).of(3.75f)
+    }
+
+    @Test
+    fun testRegisterViewOnTheLeftOfVerticalFold_zeroProgress_viewTranslatedToTheRight() {
+        givenScreen(width = 100, height = 100, rotation = ROTATION_0)
+        val view = createView(x = 20)
+        animator.registerViewForAnimation(view)
+        animator.onTransitionStarted()
+
+        animator.onTransitionProgress(0f)
+
+        // Positive translationX -> translated to the right
+        assertThat(view.translationX).isWithin(0.1f).of(7.5f)
+    }
+
+    @Test
+    fun testRegisterViewOnTheLeftOfVerticalFold_fullProgress_viewTranslatedToTheOriginalPosition() {
+        givenScreen(width = 100, height = 100, rotation = ROTATION_0)
+        val view = createView(x = 20)
+        animator.registerViewForAnimation(view)
+        animator.onTransitionStarted()
+
+        animator.onTransitionProgress(1f)
+
+        assertThat(view.translationX).isEqualTo(0f)
+    }
+
+    @Test
+    fun testRegisterViewAndUnregister_halfProgress_viewIsNotUpdated() {
+        givenScreen(width = 100, height = 100, rotation = ROTATION_0)
+        val view = createView(x = 20)
+        animator.registerViewForAnimation(view)
+        animator.onTransitionStarted()
+        animator.clearRegisteredViews()
+
+        animator.onTransitionProgress(0.5f)
+
+        assertThat(view.translationX).isEqualTo(0f)
+    }
+
+    @Test
+    fun testRegisterViewUpdateProgressAndUnregister_halfProgress_viewIsNotUpdated() {
+        givenScreen(width = 100, height = 100, rotation = ROTATION_0)
+        val view = createView(x = 20)
+        animator.registerViewForAnimation(view)
+        animator.onTransitionStarted()
+        animator.onTransitionProgress(0.2f)
+        animator.clearRegisteredViews()
+
+        animator.onTransitionProgress(0.5f)
+
+        assertThat(view.translationX).isEqualTo(0f)
+    }
+
+    @Test
+    fun testRegisterViewOnTheTopOfHorizontalFold_halfProgress_viewTranslatedToTheBottom() {
+        givenScreen(width = 100, height = 100, rotation = ROTATION_90)
+        val view = createView(y = 20)
+        animator.registerViewForAnimation(view)
+        animator.onTransitionStarted()
+
+        animator.onTransitionProgress(0.5f)
+
+        // Positive translationY -> translated to the bottom
+        assertThat(view.translationY).isWithin(0.1f).of(3.75f)
+    }
+
+    private fun createView(
+        x: Int = 0,
+        y: Int = 0,
+        width: Int = 10,
+        height: Int = 10,
+        translationX: Float = 0f,
+        translationY: Float = 0f
+    ): View {
+        val view = spy(View(context))
+        doAnswer {
+            val location = (it.arguments[0] as IntArray)
+            location[0] = x
+            location[1] = y
+            Unit
+        }.`when`(view).getLocationOnScreen(any())
+
+        whenever(view.width).thenReturn(width)
+        whenever(view.height).thenReturn(height)
+
+        return view.apply {
+            setTranslationX(translationX)
+            setTranslationY(translationY)
+        }
+    }
+
+    private fun givenScreen(width: Int = 100,
+                            height: Int = 100,
+                            rotation: Int = ROTATION_0) {
+        val display = mock(Display::class.java)
+        whenever(display.getSize(any())).thenAnswer {
+            val size = (it.arguments[0] as Point)
+            size.set(width, height)
+            Unit
+        }
+        whenever(display.rotation).thenReturn(rotation)
+        whenever(windowManager.defaultDisplay).thenReturn(display)
+
+        animator.updateDisplayProperties()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
index 325d540..790b4dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
@@ -15,7 +15,6 @@
 package com.android.systemui.shared.plugins;
 
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Matchers.any;
@@ -32,33 +31,32 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.os.HandlerThread;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import androidx.test.annotation.UiThreadTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.SysuiTestableContext;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.annotations.Requires;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
+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;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -68,63 +66,55 @@
 @RunWith(AndroidJUnit4.class)
 public class PluginInstanceManagerTest extends SysuiTestCase {
 
-    private static final String WHITELISTED_PACKAGE = "com.android.systemui";
-    // Static since the plugin needs to be generated by the PluginInstanceManager using newInstance.
-    private static Plugin sMockPlugin;
+    private static final String PRIVILEGED_PACKAGE = "com.android.systemui.shared.plugins";
+    private TestPlugin mMockPlugin;
 
-    private HandlerThread mHandlerThread;
-    private Context mContextWrapper;
     private PackageManager mMockPm;
-    private PluginListener mMockListener;
-    private PluginInstanceManager mPluginInstanceManager;
-    private PluginManagerImpl mMockManager;
+    private PluginListener<Plugin> mMockListener;
+    private PluginInstanceManager<Plugin> mPluginInstanceManager;
     private VersionInfo mMockVersionInfo;
     private PluginEnabler mMockEnabler;
     ComponentName mTestPluginComponentName =
-            new ComponentName(WHITELISTED_PACKAGE, TestPlugin.class.getName());
+            new ComponentName(PRIVILEGED_PACKAGE, TestPlugin.class.getName());
+    private PluginInitializer mInitializer;
+    private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+    NotificationManager mNotificationManager;
+    private PluginInstanceManager.Factory mInstanceManagerFactory;
+    private final PluginInstanceManager.InstanceFactory<Plugin> mPluginInstanceFactory =
+            new PluginInstanceManager.InstanceFactory<Plugin>() {
+        @Override
+        Plugin create(Class cls) {
+            return mMockPlugin;
+        }
+    };
 
     @Before
     public void setup() throws Exception {
-        mHandlerThread = new HandlerThread("test_thread");
-        mHandlerThread.start();
-        mContextWrapper = new MyContextWrapper(getContext());
+        mContext = new MyContextWrapper(mContext);
         mMockPm = mock(PackageManager.class);
         mMockListener = mock(PluginListener.class);
-        mMockManager = mock(PluginManagerImpl.class);
-        when(mMockManager.getClassLoader(any())).thenReturn(getClass().getClassLoader());
         mMockEnabler = mock(PluginEnabler.class);
-        when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
         mMockVersionInfo = mock(VersionInfo.class);
-        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
-                mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
-                mMockManager, true, new String[0]);
-        sMockPlugin = mock(Plugin.class);
-        when(sMockPlugin.getVersion()).thenReturn(1);
-    }
+        mInitializer = mock(PluginInitializer.class);
+        mNotificationManager = mock(NotificationManager.class);
+        mMockPlugin = mock(TestPlugin.class);
+        mInstanceManagerFactory = new PluginInstanceManager.Factory(getContext(), mMockPm,
+                mFakeExecutor, mFakeExecutor, mInitializer, mNotificationManager, mMockEnabler,
+                new ArrayList<>())
+                .setInstanceFactory(mPluginInstanceFactory);
 
-    @After
-    public void tearDown() throws Exception {
-        mHandlerThread.quit();
-        sMockPlugin = null;
-    }
-
-    @UiThreadTest
-    @Test
-    public void testGetPlugin() throws Exception {
-        setupFakePmQuery();
-        PluginInfo p = mPluginInstanceManager.getPlugin();
-        assertNotNull(p.mPlugin);
-        verify(sMockPlugin).onCreate(any(), any());
+        mPluginInstanceManager = mInstanceManagerFactory.create("myAction", mMockListener,
+                true, mMockVersionInfo, true);
+        when(mMockPlugin.getVersion()).thenReturn(1);
     }
 
     @Test
-    public void testNoPlugins() throws Exception {
+    public void testNoPlugins() {
         when(mMockPm.queryIntentServices(any(), anyInt())).thenReturn(
                 Collections.emptyList());
         mPluginInstanceManager.loadAll();
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+        mFakeExecutor.runAllReady();
 
         verify(mMockListener, never()).onPluginConnected(any(), any());
     }
@@ -134,7 +124,7 @@
         createPlugin();
 
         // Verify startup lifecycle
-        verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
+        verify(mMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
                 ArgumentCaptor.forClass(Context.class).capture());
         verify(mMockListener).onPluginConnected(any(), any());
     }
@@ -145,45 +135,41 @@
 
         mPluginInstanceManager.destroy();
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+        mFakeExecutor.runAllReady();
+
 
         // Verify shutdown lifecycle
         verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture());
-        verify(sMockPlugin).onDestroy();
+        verify(mMockPlugin).onDestroy();
     }
 
     @Test
     public void testIncorrectVersion() throws Exception {
-        NotificationManager nm = mock(NotificationManager.class);
-        mContext.addMockSystemService(Context.NOTIFICATION_SERVICE, nm);
         setupFakePmQuery();
         doThrow(new InvalidVersionException("", false)).when(mMockVersionInfo).checkVersion(any());
 
         mPluginInstanceManager.loadAll();
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+        mFakeExecutor.runAllReady();
 
         // Plugin shouldn't be connected because it is the wrong version.
         verify(mMockListener, never()).onPluginConnected(any(), any());
-        verify(nm).notify(eq(SystemMessage.NOTE_PLUGIN), any());
+        verify(mNotificationManager).notify(eq(SystemMessage.NOTE_PLUGIN), any());
     }
 
     @Test
     public void testReloadOnChange() throws Exception {
         createPlugin(); // Get into valid created state.
 
-        mPluginInstanceManager.onPackageChange("com.android.systemui");
+        mPluginInstanceManager.onPackageChange(PRIVILEGED_PACKAGE);
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+        mFakeExecutor.runAllReady();
 
         // Verify the old one was destroyed.
         verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture());
-        verify(sMockPlugin).onDestroy();
+        verify(mMockPlugin).onDestroy();
         // Also verify we got a second onCreate.
-        verify(sMockPlugin, Mockito.times(2)).onCreate(
+        verify(mMockPlugin, Mockito.times(2)).onCreate(
                 ArgumentCaptor.forClass(Context.class).capture(),
                 ArgumentCaptor.forClass(Context.class).capture());
         verify(mMockListener, Mockito.times(2)).onPluginConnected(any(), any());
@@ -192,35 +178,35 @@
     @Test
     public void testNonDebuggable() throws Exception {
         // Create a version that thinks the build is not debuggable.
-        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
-                mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
-                mMockManager, false, new String[0]);
+        mPluginInstanceManager = mInstanceManagerFactory.create("myAction", mMockListener,
+                true, mMockVersionInfo, false);
         setupFakePmQuery();
 
         mPluginInstanceManager.loadAll();
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);;
+        mFakeExecutor.runAllReady();
 
         // Non-debuggable build should receive no plugins.
         verify(mMockListener, never()).onPluginConnected(any(), any());
     }
 
     @Test
-    public void testNonDebuggable_whitelist() throws Exception {
+    public void testNonDebuggable_privileged() throws Exception {
         // Create a version that thinks the build is not debuggable.
-        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
-                mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
-                mMockManager, false, new String[] {WHITELISTED_PACKAGE});
+        PluginInstanceManager.Factory factory = new PluginInstanceManager.Factory(getContext(),
+                mMockPm, mFakeExecutor, mFakeExecutor, mInitializer, mNotificationManager,
+                mMockEnabler, Collections.singletonList(PRIVILEGED_PACKAGE));
+        factory.setInstanceFactory(mPluginInstanceFactory);
+        mPluginInstanceManager = factory.create("myAction", mMockListener,
+                true, mMockVersionInfo, false);
         setupFakePmQuery();
 
         mPluginInstanceManager.loadAll();
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+        mFakeExecutor.runAllReady();
 
         // Verify startup lifecycle
-        verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
+        verify(mMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
                 ArgumentCaptor.forClass(Context.class).capture());
         verify(mMockListener).onPluginConnected(any(), any());
     }
@@ -253,9 +239,13 @@
 
     @Test
     public void testDisableWhitelisted() throws Exception {
-        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
-                mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
-                mMockManager, false, new String[] {WHITELISTED_PACKAGE});
+        PluginInstanceManager.Factory factory = new PluginInstanceManager.Factory(getContext(),
+                mMockPm, mFakeExecutor, mFakeExecutor, mInitializer, mNotificationManager,
+                mMockEnabler, Collections.singletonList(PRIVILEGED_PACKAGE));
+        factory.setInstanceFactory(mPluginInstanceFactory);
+        mPluginInstanceManager = factory.create("myAction", mMockListener,
+                true, mMockVersionInfo, false);
+
         createPlugin(); // Get into valid created state.
 
         mPluginInstanceManager.disableAll();
@@ -280,9 +270,12 @@
         when(mMockPm.checkPermission(Mockito.anyString(), Mockito.anyString())).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
 
-        ApplicationInfo appInfo = getContext().getApplicationInfo();
-        when(mMockPm.getApplicationInfo(Mockito.anyString(), Mockito.anyInt())).thenReturn(
-                appInfo);
+        when(mMockPm.getApplicationInfo(Mockito.anyString(), anyInt())).thenAnswer(
+                (Answer<ApplicationInfo>) invocation -> {
+                    ApplicationInfo appInfo = getContext().getApplicationInfo();
+                    appInfo.packageName = invocation.getArgument(0);
+                    return appInfo;
+                });
         when(mMockEnabler.isEnabled(mTestPluginComponentName)).thenReturn(true);
     }
 
@@ -291,12 +284,11 @@
 
         mPluginInstanceManager.loadAll();
 
-        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
-        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+        mFakeExecutor.runAllReady();
     }
 
     // Real context with no registering/unregistering of receivers.
-    private static class MyContextWrapper extends ContextWrapper {
+    private static class MyContextWrapper extends SysuiTestableContext {
         public MyContextWrapper(Context base) {
             super(base);
         }
@@ -322,17 +314,15 @@
     public static class TestPlugin implements Plugin {
         @Override
         public int getVersion() {
-            return sMockPlugin.getVersion();
+            return 1;
         }
 
         @Override
         public void onCreate(Context sysuiContext, Context pluginContext) {
-            sMockPlugin.onCreate(sysuiContext, pluginContext);
         }
 
         @Override
         public void onDestroy() {
-            sMockPlugin.onDestroy();
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index 536c043..4590dd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -13,10 +13,8 @@
  */
 package com.android.systemui.shared.plugins;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -30,19 +28,13 @@
 import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginEnablerImpl;
-import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
-import com.android.systemui.shared.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,19 +43,24 @@
 import org.mockito.Mockito;
 
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Optional;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class PluginManagerTest extends SysuiTestCase {
 
-    private static final String WHITELISTED_PACKAGE = "com.android.systemui";
+    private static final String PRIVILEGED_PACKAGE = "com.android.systemui";
 
-    private PluginInstanceManagerFactory mMockFactory;
-    private PluginInstanceManager mMockPluginInstance;
+    private PluginInstanceManager.Factory mMockFactory;
+    private PluginInstanceManager<Plugin> mMockPluginInstance;
     private PluginManagerImpl mPluginManager;
-    private PluginListener mMockListener;
+    private PluginListener<?> mMockListener;
     private PackageManager mMockPackageManager;
+    private PluginEnabler mPluginEnabler;
+    private PluginPrefs mPluginPrefs;
 
     private UncaughtExceptionHandler mRealExceptionHandler;
     private UncaughtExceptionHandler mMockExceptionHandler;
@@ -71,44 +68,25 @@
 
     @Before
     public void setup() throws Exception {
-        mDependency.injectTestDependency(Dependency.BG_LOOPER,
-                TestableLooper.get(this).getLooper());
         mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler();
         mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
-        mMockFactory = mock(PluginInstanceManagerFactory.class);
+        mMockFactory = mock(PluginInstanceManager.Factory.class);
         mMockPluginInstance = mock(PluginInstanceManager.class);
-        when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
-                Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any()))
+        mPluginEnabler = mock(PluginEnabler.class);
+        mPluginPrefs = mock(PluginPrefs.class);
+        when(mMockFactory.create(any(), any(), Mockito.anyBoolean(), any(), Mockito.anyBoolean()))
                 .thenReturn(mMockPluginInstance);
 
         mMockPackageManager = mock(PackageManager.class);
         mPluginManager = new PluginManagerImpl(
                 getContext(), mMockFactory, true,
-                mMockExceptionHandler, new PluginInitializerImpl() {
-                    @Override
-                    public String[] getWhitelistedPlugins(Context context) {
-                        return new String[0];
-                    }
+                Optional.of(mMockExceptionHandler), mPluginEnabler,
+                mPluginPrefs, new ArrayList<>());
 
-                    @Override
-                    public PluginEnabler getPluginEnabler(Context context) {
-                        return new PluginEnablerImpl(context, mMockPackageManager);
-                    }
-        });
         resetExceptionHandler();
         mMockListener = mock(PluginListener.class);
     }
 
-    @RunWithLooper(setAsMainLooper = true)
-    @Test
-    public void testOneShot() {
-        Plugin mockPlugin = mock(Plugin.class);
-        when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
-                null, null));
-        Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
-        assertSame(mockPlugin, result);
-    }
-
     @Test
     public void testAddListener() {
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
@@ -126,53 +104,49 @@
 
     @Test
     @RunWithLooper(setAsMainLooper = true)
-    public void testNonDebuggable_noWhitelist() {
-        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
-                mMockExceptionHandler, new PluginInitializerImpl() {
-            @Override
-            public String[] getWhitelistedPlugins(Context context) {
-                return new String[0];
-            }
-        });
+    public void testNonDebuggable_nonPrivileged() {
+        mPluginManager = new PluginManagerImpl(
+                getContext(), mMockFactory, false,
+                Optional.of(mMockExceptionHandler), mPluginEnabler,
+                mPluginPrefs, new ArrayList<>());
         resetExceptionHandler();
 
         String sourceDir = "myPlugin";
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.sourceDir = sourceDir;
-        applicationInfo.packageName = WHITELISTED_PACKAGE;
+        applicationInfo.packageName = PRIVILEGED_PACKAGE;
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        assertNull(mPluginManager.getOneShotPlugin(sourceDir, TestPlugin.class));
-        assertNull(mPluginManager.getClassLoader(applicationInfo));
+        verify(mMockFactory).create(eq("myAction"), eq(mMockListener), eq(false),
+                any(VersionInfo.class), eq(false));
+        verify(mMockPluginInstance).loadAll();
     }
 
     @Test
     @RunWithLooper(setAsMainLooper = true)
-    public void testNonDebuggable_whitelistedPkg() {
-        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
-                mMockExceptionHandler, new PluginInitializerImpl() {
-            @Override
-            public String[] getWhitelistedPlugins(Context context) {
-                return new String[] {WHITELISTED_PACKAGE};
-            }
-        });
+    public void testNonDebuggable_privilegedPackage() {
+        mPluginManager = new PluginManagerImpl(
+                getContext(), mMockFactory, false,
+                Optional.of(mMockExceptionHandler), mPluginEnabler,
+                mPluginPrefs, Collections.singletonList(PRIVILEGED_PACKAGE));
         resetExceptionHandler();
 
         String sourceDir = "myPlugin";
-        ApplicationInfo whiteListedApplicationInfo = new ApplicationInfo();
-        whiteListedApplicationInfo.sourceDir = sourceDir;
-        whiteListedApplicationInfo.packageName = WHITELISTED_PACKAGE;
+        ApplicationInfo privilegedApplicationInfo = new ApplicationInfo();
+        privilegedApplicationInfo.sourceDir = sourceDir;
+        privilegedApplicationInfo.packageName = PRIVILEGED_PACKAGE;
         ApplicationInfo invalidApplicationInfo = new ApplicationInfo();
         invalidApplicationInfo.sourceDir = sourceDir;
         invalidApplicationInfo.packageName = "com.android.invalidpackage";
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        assertNotNull(mPluginManager.getClassLoader(whiteListedApplicationInfo));
-        assertNull(mPluginManager.getClassLoader(invalidApplicationInfo));
+        verify(mMockFactory).create(eq("myAction"), eq(mMockListener), eq(false),
+                any(VersionInfo.class), eq(false));
+        verify(mMockPluginInstance).loadAll();
     }
 
     @Test
     public void testExceptionHandler_foundPlugin() {
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        when(mMockPluginInstance.checkAndDisable(Mockito.any())).thenReturn(true);
+        when(mMockPluginInstance.checkAndDisable(any())).thenReturn(true);
 
         mPluginExceptionHandler.uncaughtException(Thread.currentThread(), new Throwable());
 
@@ -187,7 +161,7 @@
     @Test
     public void testExceptionHandler_noFoundPlugin() {
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        when(mMockPluginInstance.checkAndDisable(Mockito.any())).thenReturn(false);
+        when(mMockPluginInstance.checkAndDisable(any())).thenReturn(false);
 
         mPluginExceptionHandler.uncaughtException(Thread.currentThread(), new Throwable());
 
@@ -211,9 +185,7 @@
         intent.setData(Uri.parse("package://" + testComponent.flattenToString()));
         mPluginManager.onReceive(mContext, intent);
         verify(nm).cancel(eq(testComponent.getClassName()), eq(SystemMessage.NOTE_PLUGIN));
-        verify(mMockPackageManager).setComponentEnabledSetting(eq(testComponent),
-                eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
-                eq(PackageManager.DONT_KILL_APP));
+        verify(mPluginEnabler).setDisabled(testComponent, PluginEnabler.DISABLED_INVALID_VERSION);
     }
 
     private void resetExceptionHandler() {
@@ -223,8 +195,8 @@
     }
 
     @ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
-    public static interface TestPlugin extends Plugin {
-        public static final String ACTION = "testAction";
-        public static final int VERSION = 1;
+    public interface TestPlugin extends Plugin {
+        String ACTION = "testAction";
+        int VERSION = 1;
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index be7917a..2416132 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -425,17 +425,18 @@
         final boolean credentialAllowed = true;
         final boolean requireConfirmation = true;
         final int userId = 10;
-        final String packageName = "test";
         final long operationId = 1;
+        final String packageName = "test";
+        final long requestId = 10;
         final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
 
         mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
-                credentialAllowed, requireConfirmation , userId, packageName, operationId,
+                credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId,
                 multiSensorConfig);
         waitForIdleSync();
         verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
-                eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName),
-                eq(operationId), eq(multiSensorConfig));
+                eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId),
+                eq(packageName), eq(requestId), eq(multiSensorConfig));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index f5ce673..4c90063 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -111,6 +111,7 @@
     private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
             "bar");
 
+    private String mKeyguardTryFingerprintMsg;
     private String mDisclosureWithOrganization;
     private String mDisclosureGeneric;
     private String mFinancedDisclosureWithOrganization;
@@ -182,6 +183,7 @@
         mContext.addMockSystemService(UserManager.class, mUserManager);
         mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
         mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
+        mKeyguardTryFingerprintMsg = mContext.getString(R.string.keyguard_try_fingerprint);
         mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
                 ORGANIZATION_NAME);
         mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
@@ -677,6 +679,34 @@
         verifyTransientMessage(message);
     }
 
+    @Test
+    public void faceAuthMessageSuppressed() {
+        createController();
+        String faceHelpMsg = "Face auth help message";
+
+        // GIVEN state of showing message when keyguard screen is on
+        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
+
+        // GIVEN fingerprint is also running (not udfps)
+        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isUdfpsAvailable()).thenReturn(false);
+
+        mController.setVisible(true);
+
+        // WHEN a face help message comes in
+        mController.getKeyguardCallback().onBiometricHelp(
+                KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, faceHelpMsg,
+                BiometricSourceType.FACE);
+
+        // THEN "try fingerprint" message appears (and not the face help message)
+        verifyTransientMessage(mKeyguardTryFingerprintMsg);
+
+        // THEN the face help message is still announced for a11y
+        verify(mIndicationAreaBottom).announceForAccessibility(eq(faceHelpMsg));
+    }
+
     private void sendUpdateDisclosureBroadcast() {
         mBroadcastReceiver.onReceive(mContext, new Intent());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
new file mode 100644
index 0000000..97fe25d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.function.Consumer
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LightRevealScrimTest : SysuiTestCase() {
+
+  private lateinit var scrim: LightRevealScrim
+  private var isOpaque = false
+
+  @Before
+  fun setUp() {
+    scrim = LightRevealScrim(context, null)
+    scrim.isScrimOpaqueChangedListener = Consumer { opaque ->
+      isOpaque = opaque
+    }
+    scrim.revealAmount = 0f
+    assertTrue("Scrim is not opaque in initial setup", scrim.isScrimOpaque)
+  }
+
+  @Test
+  fun testAlphaSetsOpaque() {
+    scrim.alpha = 0.5f
+    assertFalse("Scrim is opaque even though alpha is set", scrim.isScrimOpaque)
+  }
+
+  @Test
+  fun testVisibilitySetsOpaque() {
+    scrim.visibility = View.INVISIBLE
+    assertFalse("Scrim is opaque even though it's invisible", scrim.isScrimOpaque)
+    scrim.visibility = View.GONE
+    assertFalse("Scrim is opaque even though it's gone", scrim.isScrimOpaque)
+  }
+
+  @Test
+  fun testRevealSetsOpaque() {
+    scrim.revealAmount = 0.5f
+    assertFalse("Scrim is opaque even though it's revealed", scrim.isScrimOpaque)
+  }
+}
\ No newline at end of file
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..7f72f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -25,6 +25,7 @@
 import android.view.ViewRootImpl
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.BiometricUnlockController
@@ -69,7 +70,6 @@
     @Mock private lateinit var root: View
     @Mock private lateinit var viewRootImpl: ViewRootImpl
     @Mock private lateinit var windowToken: IBinder
-    @Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
     @Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation
     @Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
     @Mock private lateinit var listener: NotificationShadeDepthController.DepthListener
@@ -89,10 +89,10 @@
         `when`(root.isAttachedToWindow).thenReturn(true)
         `when`(statusBarStateController.state).then { statusBarState }
         `when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
-            (answer.arguments[0] as Float * maxBlur).toInt()
+            answer.arguments[0] as Float * maxBlur.toFloat()
         }
-        `when`(blurUtils.ratioOfBlurRadius(anyInt())).then { answer ->
-            answer.arguments[0] as Int / maxBlur.toFloat()
+        `when`(blurUtils.ratioOfBlurRadius(anyFloat())).then { answer ->
+            answer.arguments[0] as Float / maxBlur.toFloat()
         }
         `when`(blurUtils.supportsBlursOnWindows()).thenReturn(true)
         `when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
@@ -102,7 +102,6 @@
                 statusBarStateController, blurUtils, biometricUnlockController,
                 keyguardStateController, choreographer, wallpaperManager,
                 notificationShadeWindowController, dozeParameters, dumpManager)
-        notificationShadeDepthController.shadeSpring = shadeSpring
         notificationShadeDepthController.shadeAnimation = shadeAnimation
         notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
         notificationShadeDepthController.root = root
@@ -123,7 +122,6 @@
     fun onPanelExpansionChanged_apliesBlur_ifShade() {
         notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
                 false /* tracking */)
-        verify(shadeSpring).animateTo(eq(maxBlur), any())
         verify(shadeAnimation).animateTo(eq(maxBlur), any())
     }
 
@@ -172,23 +170,33 @@
     @Test
     fun onStateChanged_reevalutesBlurs_ifSameRadiusAndNewState() {
         onPanelExpansionChanged_apliesBlur_ifShade()
-        clearInvocations(shadeSpring)
-        clearInvocations(shadeAnimation)
+        clearInvocations(choreographer)
 
         statusBarState = StatusBarState.KEYGUARD
         statusBarStateListener.onStateChanged(statusBarState)
-        verify(shadeSpring).animateTo(eq(0), any())
         verify(shadeAnimation).animateTo(eq(0), any())
     }
 
     @Test
     fun setQsPanelExpansion_appliesBlur() {
+        statusBarState = StatusBarState.KEYGUARD
         notificationShadeDepthController.qsPanelExpansion = 1f
+        notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false)
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
     }
 
     @Test
+    fun setQsPanelExpansion_easing() {
+        statusBarState = StatusBarState.KEYGUARD
+        notificationShadeDepthController.qsPanelExpansion = 0.25f
+        notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false)
+        notificationShadeDepthController.updateBlurCallback.doFrame(0)
+        verify(wallpaperManager).setWallpaperZoomOut(any(),
+                eq(Interpolators.getNotificationScrimAlpha(0.25f, false /* notifications */)))
+    }
+
+    @Test
     fun setFullShadeTransition_appliesBlur() {
         notificationShadeDepthController.transitionToFullShadeProgress = 1f
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
@@ -206,10 +214,10 @@
     fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
         reset(blurUtils)
         `when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
-            (answer.arguments[0] as Float * maxBlur).toInt()
+            answer.arguments[0] as Float * maxBlur
         }
-        `when`(blurUtils.ratioOfBlurRadius(anyInt())).then { answer ->
-            answer.arguments[0] as Int / maxBlur.toFloat()
+        `when`(blurUtils.ratioOfBlurRadius(anyFloat())).then { answer ->
+            answer.arguments[0] as Float / maxBlur.toFloat()
         }
         `when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
         `when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
@@ -238,16 +246,16 @@
 
     @Test
     fun updateBlurCallback_setsBlur_whenExpanded() {
-        `when`(shadeSpring.radius).thenReturn(maxBlur)
-        `when`(shadeAnimation.radius).thenReturn(maxBlur)
+        notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+        `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
     }
 
     @Test
     fun updateBlurCallback_ignoreShadeBlurUntilHidden_overridesZoom() {
-        `when`(shadeSpring.radius).thenReturn(maxBlur)
-        `when`(shadeAnimation.radius).thenReturn(maxBlur)
+        notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+        `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
         notificationShadeDepthController.blursDisabledForAppLaunch = true
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(0), eq(false))
@@ -292,8 +300,8 @@
         // Brightness mirror is fully visible
         `when`(brightnessSpring.ratio).thenReturn(1f)
         // And shade is blurred
-        `when`(shadeSpring.radius).thenReturn(maxBlur)
-        `when`(shadeAnimation.radius).thenReturn(maxBlur)
+        notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+        `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
 
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(notificationShadeWindowController).setBackgroundBlurRadius(eq(0))
@@ -303,10 +311,8 @@
 
     @Test
     fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
-        `when`(shadeSpring.radius).thenReturn(0)
-        `when`(shadeAnimation.radius).thenReturn(0)
+        `when`(shadeAnimation.radius).thenReturn(0f)
         notificationShadeDepthController.blursDisabledForAppLaunch = true
-        verify(shadeSpring, never()).animateTo(anyInt(), any())
         verify(shadeAnimation, never()).animateTo(anyInt(), any())
     }
 }
\ No newline at end of file
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 756e984..a2bb0af 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
@@ -389,6 +389,7 @@
         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/collection/EntryUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
index 62667bc..da956ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
@@ -30,3 +30,7 @@
     modifier(builder)
     builder.apply(entry)
 }
+
+fun getAttachState(entry: ListEntry): ListAttachState {
+    return entry.attachState
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 2ce22a6..3378003 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -802,13 +802,13 @@
                 .onBeforeTransformGroups(anyList());
         inOrder.verify(promoter, atLeastOnce())
                 .shouldPromoteToTopLevel(any(NotificationEntry.class));
+        inOrder.verify(mOnBeforeFinalizeFilterListener).onBeforeFinalizeFilter(anyList());
+        inOrder.verify(preRenderFilter, atLeastOnce())
+                .shouldFilterOut(any(NotificationEntry.class), anyLong());
         inOrder.verify(mOnBeforeSortListener).onBeforeSort(anyList());
         inOrder.verify(section, atLeastOnce()).isInSection(any(ListEntry.class));
         inOrder.verify(comparator, atLeastOnce())
                 .compare(any(ListEntry.class), any(ListEntry.class));
-        inOrder.verify(mOnBeforeFinalizeFilterListener).onBeforeFinalizeFilter(anyList());
-        inOrder.verify(preRenderFilter, atLeastOnce())
-                .shouldFilterOut(any(NotificationEntry.class), anyLong());
         inOrder.verify(mOnBeforeRenderListListener).onBeforeRenderList(anyList());
         inOrder.verify(mOnRenderListListener).onRenderList(anyList());
     }
@@ -1045,12 +1045,32 @@
         // because group changes aren't allowed by the stability manager
         verifyBuiltList(
                 notif(0),
+                notif(2),
                 group(
                         summary(3),
                         child(4),
                         child(5)
-                ),
-                notif(2)
+                )
+        );
+    }
+
+    @Test
+    public void testBrokenGroupNotificationOrdering() {
+        // GIVEN two group children with different sections & without a summary yet
+
+        addGroupChild(0, PACKAGE_2, GROUP_1);
+        addNotif(1, PACKAGE_1);
+        addGroupChild(2, PACKAGE_2, GROUP_1);
+        addGroupChild(3, PACKAGE_2, GROUP_1);
+
+        dispatchBuild();
+
+        // THEN all notifications are not grouped and posted in order by index
+        verifyBuiltList(
+                notif(0),
+                notif(1),
+                notif(2),
+                notif(3)
         );
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
new file mode 100644
index 0000000..01e4cce0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.collection.coordinator;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.communal.CommunalStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@SmallTest
+public class CommunalCoordinatorTest extends SysuiTestCase {
+    @Mock
+    CommunalStateController mCommunalStateController;
+    @Mock
+    NotificationEntryManager mNotificationEntryManager;
+    @Mock
+    NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+    @Mock
+    NotifPipeline mNotifPipeline;
+    @Mock
+    NotificationEntry mNotificationEntry;
+    @Mock
+    Pluggable.PluggableListener mFilterListener;
+
+    CommunalCoordinator mCoordinator;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mCoordinator = new CommunalCoordinator(mNotificationEntryManager,
+                mNotificationLockscreenUserManager, mCommunalStateController);
+    }
+
+    @Test
+    public void testNotificationSuppressionInCommunal() {
+        mCoordinator.attach(mNotifPipeline);
+        final ArgumentCaptor<CommunalStateController.Callback> stateCallbackCaptor =
+                ArgumentCaptor.forClass(CommunalStateController.Callback.class);
+        verify(mCommunalStateController).addCallback(stateCallbackCaptor.capture());
+
+        final CommunalStateController.Callback stateCallback = stateCallbackCaptor.getValue();
+
+        final ArgumentCaptor<NotifFilter> filterCaptor =
+                ArgumentCaptor.forClass(NotifFilter.class);
+        verify(mNotifPipeline).addPreGroupFilter(filterCaptor.capture());
+
+        final NotifFilter filter = filterCaptor.getValue();
+
+        // Verify that notifications are not filtered out by default.
+        assert (!filter.shouldFilterOut(mNotificationEntry, 0));
+
+        filter.setInvalidationListener(mFilterListener);
+
+        // Verify that notifications are filtered out when communal is showing and that the filter
+        // pipeline is notified.
+        stateCallback.onCommunalViewShowingChanged();
+        verify(mFilterListener).onPluggableInvalidated(any());
+        verify(mNotificationEntryManager).updateNotifications(any());
+        assert (filter.shouldFilterOut(mNotificationEntry, 0));
+
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
new file mode 100644
index 0000000..2e676bb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -0,0 +1,311 @@
+/*
+ * 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.collection.render
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.getAttachState
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.util.mockito.any
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class NodeSpecBuilderTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var viewBarn: NotifViewBarn
+
+    private var rootController: NodeController = buildFakeController("rootController")
+    private var headerController0: NodeController = buildFakeController("header0")
+    private var headerController1: NodeController = buildFakeController("header1")
+    private var headerController2: NodeController = buildFakeController("header2")
+
+    private val section0 = buildSection(0, headerController0)
+    private val section0NoHeader = buildSection(0, null)
+    private val section1 = buildSection(1, headerController1)
+    private val section1NoHeader = buildSection(1, null)
+    private val section2 = buildSection(2, headerController2)
+
+    private val fakeViewBarn = FakeViewBarn()
+
+    private lateinit var specBuilder: NodeSpecBuilder
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        `when`(viewBarn.requireView(any())).thenAnswer {
+            fakeViewBarn.getViewByEntry(it.getArgument(0))
+        }
+
+        specBuilder = NodeSpecBuilder(viewBarn)
+    }
+
+    @Test
+    fun testSimpleMapping() {
+        checkOutput(
+                // GIVEN a simple flat list of notifications all in the same headerless section
+                listOf(
+                        notif(0, section0NoHeader),
+                        notif(1, section0NoHeader),
+                        notif(2, section0NoHeader),
+                        notif(3, section0NoHeader)
+                ),
+
+                // THEN we output a similarly simple flag list of nodes
+                tree(
+                        notifNode(0),
+                        notifNode(1),
+                        notifNode(2),
+                        notifNode(3)
+                )
+        )
+    }
+
+    @Test
+    fun testHeaderInjection() {
+        checkOutput(
+                // GIVEN a flat list of notifications, spread across three sections
+                listOf(
+                        notif(0, section0),
+                        notif(1, section0),
+                        notif(2, section1),
+                        notif(3, section2)
+                ),
+
+                // THEN each section has its header injected
+                tree(
+                        node(headerController0),
+                        notifNode(0),
+                        notifNode(1),
+                        node(headerController1),
+                        notifNode(2),
+                        node(headerController2),
+                        notifNode(3)
+                )
+        )
+    }
+
+    @Test
+    fun testGroups() {
+        checkOutput(
+                // GIVEN a mixed list of top-level notifications and groups
+                listOf(
+                    notif(0, section0),
+                    group(1, section1,
+                            notif(2),
+                            notif(3),
+                            notif(4)
+                    ),
+                    notif(5, section2),
+                    group(6, section2,
+                            notif(7),
+                            notif(8),
+                            notif(9)
+                    )
+                ),
+
+                // THEN we properly construct all the nodes
+                tree(
+                        node(headerController0),
+                        notifNode(0),
+                        node(headerController1),
+                        notifNode(1,
+                                notifNode(2),
+                                notifNode(3),
+                                notifNode(4)
+                        ),
+                        node(headerController2),
+                        notifNode(5),
+                        notifNode(6,
+                                notifNode(7),
+                                notifNode(8),
+                                notifNode(9)
+                        )
+                )
+        )
+    }
+
+    @Test
+    fun testSecondSectionWithNoHeader() {
+        checkOutput(
+                // GIVEN a middle section with no associated header view
+                listOf(
+                        notif(0, section0),
+                        notif(1, section1NoHeader),
+                        group(2, section1NoHeader,
+                                notif(3),
+                                notif(4)
+                        ),
+                        notif(5, section2)
+                ),
+
+                // THEN the header view is left out of the tree (but the notifs are still present)
+                tree(
+                        node(headerController0),
+                        notifNode(0),
+                        notifNode(1),
+                        notifNode(2,
+                                notifNode(3),
+                                notifNode(4)
+                        ),
+                        node(headerController2),
+                        notifNode(5)
+                )
+        )
+    }
+
+    @Test(expected = RuntimeException::class)
+    fun testRepeatedSectionsThrow() {
+        checkOutput(
+                // GIVEN a malformed list where sections are not contiguous
+                listOf(
+                        notif(0, section0),
+                        notif(1, section1),
+                        notif(2, section0)
+                ),
+
+                // THEN an exception is thrown
+                tree()
+        )
+    }
+
+    private fun checkOutput(list: List<ListEntry>, desiredTree: NodeSpecImpl) {
+        checkTree(desiredTree, specBuilder.buildNodeSpec(rootController, list))
+    }
+
+    private fun checkTree(desiredTree: NodeSpec, actualTree: NodeSpec) {
+        try {
+            checkNode(desiredTree, actualTree)
+        } catch (e: AssertionError) {
+            throw AssertionError("Trees don't match: ${e.message}\nActual tree:\n" +
+                    treeSpecToStr(actualTree))
+        }
+    }
+
+    private fun checkNode(desiredTree: NodeSpec, actualTree: NodeSpec) {
+        if (actualTree.controller != desiredTree.controller) {
+            throw AssertionError("Node {${actualTree.controller.nodeLabel}} should " +
+                    "be ${desiredTree.controller.nodeLabel}")
+        }
+        for (i in 0 until desiredTree.children.size) {
+            if (i >= actualTree.children.size) {
+                throw AssertionError("Node {${actualTree.controller.nodeLabel}}" +
+                        " is missing child ${desiredTree.children[i].controller.nodeLabel}")
+            }
+            checkNode(desiredTree.children[i], actualTree.children[i])
+        }
+    }
+
+    private fun notif(id: Int, section: NotifSection? = null): NotificationEntry {
+        val entry = NotificationEntryBuilder()
+                .setId(id)
+                .build()
+        if (section != null) {
+            getAttachState(entry).section = section
+        }
+        fakeViewBarn.buildNotifView(id, entry)
+        return entry
+    }
+
+    private fun group(
+        id: Int,
+        section: NotifSection,
+        vararg children: NotificationEntry
+    ): GroupEntry {
+        val group = GroupEntryBuilder()
+                .setKey("group_$id")
+                .setSummary(
+                        NotificationEntryBuilder()
+                                .setId(id)
+                                .build())
+                .setChildren(children.asList())
+                .build()
+        getAttachState(group).section = section
+        fakeViewBarn.buildNotifView(id, group.summary!!)
+
+        for (child in children) {
+            getAttachState(child).section = section
+        }
+        return group
+    }
+
+    private fun tree(vararg children: NodeSpecImpl): NodeSpecImpl {
+        return node(rootController, *children)
+    }
+
+    private fun node(view: NodeController, vararg children: NodeSpecImpl): NodeSpecImpl {
+        val node = NodeSpecImpl(null, view)
+        node.children.addAll(children)
+        return node
+    }
+
+    private fun notifNode(id: Int, vararg children: NodeSpecImpl): NodeSpecImpl {
+        return node(fakeViewBarn.getViewById(id), *children)
+    }
+}
+
+private class FakeViewBarn {
+    private val entries = mutableMapOf<Int, NotificationEntry>()
+    private val views = mutableMapOf<NotificationEntry, NodeController>()
+
+    fun buildNotifView(id: Int, entry: NotificationEntry) {
+        if (entries.contains(id)) {
+            throw RuntimeException("ID $id is already in use")
+        }
+        entries[id] = entry
+        views[entry] = buildFakeController("Entry $id")
+    }
+
+    fun getViewById(id: Int): NodeController {
+        return views[entries[id] ?: throw RuntimeException("No view with ID $id")]!!
+    }
+
+    fun getViewByEntry(entry: NotificationEntry): NodeController {
+        return views[entry] ?: throw RuntimeException("No view defined for key ${entry.key}")
+    }
+}
+
+private fun buildFakeController(name: String): NodeController {
+    val controller = Mockito.mock(NodeController::class.java)
+    `when`(controller.nodeLabel).thenReturn(name)
+    return controller
+}
+
+private fun buildSection(index: Int, nodeController: NodeController?): NotifSection {
+    return NotifSection(object : NotifSectioner("Section $index") {
+
+        override fun isInSection(entry: ListEntry?): Boolean {
+            throw NotImplementedError("This should never be called")
+        }
+
+        override fun getHeaderNodeController(): NodeController? {
+            return nodeController
+        }
+    }, index)
+}
\ No newline at end of file
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 0854b93..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
@@ -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/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 0772c03..d3c1dc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -37,14 +37,12 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.util.HashSet;
@@ -59,8 +57,6 @@
     private Runnable mRoundnessCallback = mock(Runnable.class);
     private ExpandableNotificationRow mFirst;
     private ExpandableNotificationRow mSecond;
-    @Mock
-    private KeyguardBypassController mBypassController;
     private float mSmallRadiusRatio;
 
     @Before
@@ -70,7 +66,6 @@
         mSmallRadiusRatio = resources.getDimension(R.dimen.notification_corner_radius_small)
                 / resources.getDimension(R.dimen.notification_corner_radius);
         mRoundnessManager = new NotificationRoundnessManager(
-                mBypassController,
                 new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext));
         allowTestableLooperAsMainThread();
         NotificationTestHelper testHelper = new NotificationTestHelper(
@@ -90,6 +85,7 @@
                 createSection(null, null)
         });
         mRoundnessManager.setExpanded(1.0f, 1.0f);
+        mRoundnessManager.setShouldRoundPulsingViews(true);
         reset(mRoundnessCallback);
     }
 
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 55c69f7..e159cae 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
@@ -17,6 +17,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
@@ -40,6 +41,7 @@
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -72,6 +74,8 @@
 
     private final StatusBar mStatusBar = mock(StatusBar.class);
     private final CommandQueue mCommandQueue = mock(CommandQueue.class);
+    private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
+    private OperatorNameViewController mOperatorNameViewController;
 
 
     public CollapsedStatusBarFragmentTest() {
@@ -243,6 +247,11 @@
         mNetworkController = mock(NetworkController.class);
         mStatusBarStateController = mock(StatusBarStateController.class);
         mKeyguardStateController = mock(KeyguardStateController.class);
+        mOperatorNameViewController = mock(OperatorNameViewController.class);
+        mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
+        when(mOperatorNameViewControllerFactory.create(any()))
+                .thenReturn(mOperatorNameViewController);
+
         setUpNotificationIconAreaController();
         return new CollapsedStatusBarFragment(
                 mOngoingCallController,
@@ -255,7 +264,8 @@
                 mNetworkController,
                 mStatusBarStateController,
                 () -> Optional.of(mStatusBar),
-                mCommandQueue);
+                mCommandQueue,
+                mOperatorNameViewControllerFactory);
     }
 
 
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 2e76bd7..f34f21b 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
@@ -31,14 +31,12 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
-
     private static final int SCREEN_HEIGHT = 2000;
     private static final int EMPTY_MARGIN = 0;
     private static final int EMPTY_HEIGHT = 0;
     private static final float ZERO_DRAG = 0.f;
     private static final float OPAQUE = 1.f;
     private static final float TRANSPARENT = 0.f;
-
     private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
     private KeyguardClockPositionAlgorithm.Result mClockPosition;
     private float mPanelExpansion;
@@ -46,7 +44,6 @@
     private float mDark;
     private float mQsExpansion;
     private int mCutoutTopInsetPx = 0;
-    private int mSplitShadeSmartspaceHeightPx = 0;
     private boolean mIsSplitShade = false;
 
     @Before
@@ -214,7 +211,6 @@
         mKeyguardStatusHeight = 200;
         // WHEN the position algorithm is run
         positionClock();
-
         assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
     }
 
@@ -230,17 +226,6 @@
     }
 
     @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();
@@ -271,7 +256,6 @@
         mPanelExpansion = 0.f;
         // WHEN the clock position algorithm is run
         positionClock();
-
         assertThat(mClockPosition.stackScrollerPadding).isEqualTo(
                 (int) (mKeyguardStatusHeight * .667f));
     }
@@ -298,12 +282,11 @@
     }
 
     private void positionClock() {
-        mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT,
-                mPanelExpansion, mKeyguardStatusHeight,
+        mClockPositionAlgorithm.setup(EMPTY_MARGIN, mPanelExpansion, mKeyguardStatusHeight,
                 0 /* userSwitchHeight */, 0 /* userSwitchPreferredY */,
                 mDark, ZERO_DRAG, false /* bypassEnabled */,
                 0 /* unlockedStackScrollerPadding */, mQsExpansion,
-                mCutoutTopInsetPx, mSplitShadeSmartspaceHeightPx, mIsSplitShade);
+                mCutoutTopInsetPx, 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 9cc762c..faf968b 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
@@ -17,36 +17,49 @@
 package com.android.systemui.statusbar.phone;
 
 
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.view.ViewGroup;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.CarrierTextController;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
 public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
     @Mock
-    private KeyguardStatusBarView mKeyguardStatusBarView;
-    @Mock
-    private ViewGroup mViewGroup;
-    @Mock
     private CarrierTextController mCarrierTextController;
     @Mock
     private ConfigurationController mConfigurationController;
@@ -62,16 +75,33 @@
     private FeatureFlags mFeatureFlags;
     @Mock
     private BatteryMeterViewController mBatteryMeterViewController;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock
+    private BiometricUnlockController mBiometricUnlockController;
+    @Mock
+    private SysuiStatusBarStateController mStatusBarStateController;
 
+    private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
+    private KeyguardStatusBarView mKeyguardStatusBarView;
     private KeyguardStatusBarViewController mController;
 
     @Before
     public void setup() throws Exception {
+        mNotificationPanelViewStateProvider = new TestNotificationPanelViewStateProvider();
+
         MockitoAnnotations.initMocks(this);
 
-        when(mKeyguardStatusBarView.getResources()).thenReturn(mContext.getResources());
-        when(mKeyguardStatusBarView.findViewById(R.id.statusIcons)).thenReturn(mViewGroup);
-        when(mViewGroup.getContext()).thenReturn(mContext);
+        allowTestableLooperAsMainThread();
+        TestableLooper.get(this).runWithLooper(() -> {
+            mKeyguardStatusBarView =
+                    (KeyguardStatusBarView) LayoutInflater.from(mContext)
+                            .inflate(R.layout.keyguard_status_bar, null);
+        });
 
         mController = new KeyguardStatusBarViewController(
                 mKeyguardStatusBarView,
@@ -82,7 +112,13 @@
                 mUserInfoController,
                 mStatusBarIconController,
                 new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
-                mBatteryMeterViewController
+                mBatteryMeterViewController,
+                mNotificationPanelViewStateProvider,
+                mKeyguardStateController,
+                mKeyguardBypassController,
+                mKeyguardUpdateMonitor,
+                mBiometricUnlockController,
+                mStatusBarStateController
         );
     }
 
@@ -133,4 +169,216 @@
 
         verify(mBatteryController).addCallback(any());
     }
+
+    @Test
+    public void updateTopClipping_viewClippingUpdated() {
+        int viewTop = 20;
+        mKeyguardStatusBarView.setTop(viewTop);
+        int notificationPanelTop = 30;
+
+        mController.updateTopClipping(notificationPanelTop);
+
+        assertThat(mKeyguardStatusBarView.getClipBounds().top).isEqualTo(
+                notificationPanelTop - viewTop);
+    }
+
+    @Test
+    public void setNotTopClipping_viewClippingUpdatedToZero() {
+        // Start out with some amount of top clipping.
+        mController.updateTopClipping(50);
+        assertThat(mKeyguardStatusBarView.getClipBounds().top).isGreaterThan(0);
+
+        mController.setNoTopClipping();
+
+        assertThat(mKeyguardStatusBarView.getClipBounds().top).isEqualTo(0);
+    }
+
+    @Test
+    public void updateViewState_alphaAndVisibilityGiven_viewUpdated() {
+        // Verify the initial values so we know the method triggers changes.
+        assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(1f);
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+
+        float newAlpha = 0.5f;
+        int newVisibility = View.INVISIBLE;
+        mController.updateViewState(newAlpha, newVisibility);
+
+        assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(newAlpha);
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(newVisibility);
+    }
+
+    @Test
+    public void updateViewState_notKeyguardState_nothingUpdated() {
+        mController.onViewAttached();
+        updateStateToNotKeyguard();
+
+        float oldAlpha = mKeyguardStatusBarView.getAlpha();
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(oldAlpha);
+    }
+
+    @Test
+    public void updateViewState_bypassEnabledAndShouldListenForFace_viewHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+
+        when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        onFinishedGoingToSleep();
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    @Test
+    public void updateViewState_bypassNotEnabled_viewShown() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false);
+        onFinishedGoingToSleep();
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateViewState_shouldNotListenForFace_viewShown() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(false);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        onFinishedGoingToSleep();
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateViewState_panelExpandedHeightZero_viewHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        mNotificationPanelViewStateProvider.setPanelViewExpandedHeight(0);
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    @Test
+    public void updateViewState_qsExpansionOne_viewHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        mNotificationPanelViewStateProvider.setQsExpansionFraction(1f);
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    // TODO(b/195442899): Add more tests for #updateViewState once CLs are finalized.
+
+    @Test
+    public void updateForHeadsUp_headsUpShouldBeVisible_viewHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        mKeyguardStatusBarView.setVisibility(View.VISIBLE);
+
+        mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+        mController.updateForHeadsUp(/* animate= */ false);
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    @Test
+    public void updateForHeadsUp_headsUpShouldNotBeVisible_viewShown() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        // Start with the opposite state.
+        mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+        mController.updateForHeadsUp(/* animate= */ false);
+
+        mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(false);
+        mController.updateForHeadsUp(/* animate= */ false);
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    private void updateStateToNotKeyguard() {
+        updateStatusBarState(SHADE);
+    }
+
+    private void updateStateToKeyguard() {
+        updateStatusBarState(KEYGUARD);
+    }
+
+    private void updateStatusBarState(int state) {
+        ArgumentCaptor<StatusBarStateController.StateListener> statusBarStateListenerCaptor =
+                ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+        verify(mStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture());
+        StatusBarStateController.StateListener callback = statusBarStateListenerCaptor.getValue();
+
+        callback.onStateChanged(state);
+    }
+
+    /**
+     * Calls {@link com.android.keyguard.KeyguardUpdateMonitorCallback#onFinishedGoingToSleep(int)}
+     * to ensure values are updated properly.
+     */
+    private void onFinishedGoingToSleep() {
+        ArgumentCaptor<KeyguardUpdateMonitorCallback> keyguardUpdateCallbackCaptor =
+                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+        verify(mKeyguardUpdateMonitor).registerCallback(keyguardUpdateCallbackCaptor.capture());
+        KeyguardUpdateMonitorCallback callback = keyguardUpdateCallbackCaptor.getValue();
+
+        callback.onFinishedGoingToSleep(0);
+    }
+
+    private static class TestNotificationPanelViewStateProvider
+            implements NotificationPanelViewController.NotificationPanelViewStateProvider {
+
+        TestNotificationPanelViewStateProvider() {}
+
+        private float mPanelViewExpandedHeight = 100f;
+        private float mQsExpansionFraction = 0f;
+        private boolean mShouldHeadsUpBeVisible = false;
+
+        @Override
+        public float getPanelViewExpandedHeight() {
+            return mPanelViewExpandedHeight;
+        }
+
+        @Override
+        public float getQsExpansionFraction() {
+            return mQsExpansionFraction;
+        }
+
+        @Override
+        public boolean shouldHeadsUpBeVisible() {
+            return mShouldHeadsUpBeVisible;
+        }
+
+        public void setPanelViewExpandedHeight(float panelViewExpandedHeight) {
+            this.mPanelViewExpandedHeight = panelViewExpandedHeight;
+        }
+
+        public void setQsExpansionFraction(float qsExpansionFraction) {
+            this.mQsExpansionFraction = qsExpansionFraction;
+        }
+
+        public void setShouldHeadsUpBeVisible(boolean shouldHeadsUpBeVisible) {
+            this.mShouldHeadsUpBeVisible = shouldHeadsUpBeVisible;
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
new file mode 100644
index 0000000..3108ed9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
@@ -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.systemui.statusbar.phone;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardStatusBarViewTest extends SysuiTestCase {
+
+    private KeyguardStatusBarView mKeyguardStatusBarView;
+
+    @Before
+    public void setup() throws Exception {
+        allowTestableLooperAsMainThread();
+        TestableLooper.get(this).runWithLooper(() -> {
+            mKeyguardStatusBarView =
+                    (KeyguardStatusBarView) LayoutInflater.from(mContext)
+                            .inflate(R.layout.keyguard_status_bar, null);
+        });
+    }
+
+    @Test
+    public void setTopClipping_clippingUpdated() {
+        int topClipping = 40;
+
+        mKeyguardStatusBarView.setTopClipping(topClipping);
+
+        assertThat(mKeyguardStatusBarView.getClipBounds().top).isEqualTo(topClipping);
+    }
+}
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 11a822c..a8b2990 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
@@ -29,6 +29,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
@@ -47,7 +48,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.hardware.biometrics.BiometricSourceType;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -63,7 +63,6 @@
 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 +92,11 @@
 import com.android.systemui.communal.CommunalHostViewController;
 import com.android.systemui.communal.CommunalSource;
 import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.communal.dagger.CommunalViewComponent;
 import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.doze.DozeLog;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.idle.IdleHostViewController;
@@ -120,7 +121,6 @@
 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;
@@ -131,7 +131,10 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -178,7 +181,7 @@
     @Mock
     private KeyguardStatusBarView mKeyguardStatusBar;
     @Mock
-    private View mUserSwitcherView;
+    private KeyguardUserSwitcherView mUserSwitcherView;
     @Mock
     private ViewStub mUserSwitcherStubView;
     @Mock
@@ -198,6 +201,8 @@
     @Mock
     private LayoutInflater mLayoutInflater;
     @Mock
+    private FeatureFlags mFeatureFlags;
+    @Mock
     private DynamicPrivacyController mDynamicPrivacyController;
     @Mock
     private ShadeController mShadeController;
@@ -239,16 +244,22 @@
     @Mock
     private ConversationNotificationManager mConversationNotificationManager;
     @Mock
-    private BiometricUnlockController mBiometricUnlockController;
-    @Mock
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock
     private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
     @Mock
     private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
     @Mock
+    private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
+    @Mock
+    private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
+    @Mock
     private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
     @Mock
+    private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
+    @Mock
+    private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
+    @Mock
     private IdleViewComponent.Factory mIdleViewComponentFactory;
     @Mock
     private IdleViewComponent mIdleViewComponent;
@@ -275,6 +286,9 @@
     @Mock
     private CommunalHostView mCommunalHostView;
     @Mock
+    private CommunalStateController mCommunalStateController;
+    private CommunalStateController.Callback mCommunalStateControllerCallback;
+    @Mock
     private KeyguardClockSwitchController mKeyguardClockSwitchController;
     @Mock
     private KeyguardStatusViewController mKeyguardStatusViewController;
@@ -329,9 +343,7 @@
     @Mock
     private ControlsComponent mControlsComponent;
     @Mock
-    private LockscreenSmartspaceController mLockscreenSmartspaceController;
-    @Mock
-    private FrameLayout mSplitShadeSmartspaceContainer;
+    private LockscreenGestureLogger mLockscreenGestureLogger;
 
     private SysuiStatusBarStateController mStatusBarStateController;
     private NotificationPanelViewController mNotificationPanelViewController;
@@ -382,8 +394,6 @@
         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));
@@ -394,6 +404,14 @@
         when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
         FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
                 mDisplayMetrics);
+        when(mKeyguardQsUserSwitchComponentFactory.build(any()))
+                .thenReturn(mKeyguardQsUserSwitchComponent);
+        when(mKeyguardQsUserSwitchComponent.getKeyguardQsUserSwitchController())
+                .thenReturn(mKeyguardQsUserSwitchController);
+        when(mKeyguardUserSwitcherComponentFactory.build(any()))
+                .thenReturn(mKeyguardUserSwitcherComponent);
+        when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
+                .thenReturn(mKeyguardUserSwitcherController);
 
         doAnswer((Answer<Void>) invocation -> {
             mTouchHandler = invocation.getArgument(0);
@@ -424,7 +442,7 @@
                 .thenReturn(mKeyguardClockSwitchController);
         when(mKeyguardStatusViewComponent.getKeyguardStatusViewController())
                 .thenReturn(mKeyguardStatusViewController);
-        when(mKeyguardStatusBarViewComponentFactory.build(any()))
+        when(mKeyguardStatusBarViewComponentFactory.build(any(), any()))
                 .thenReturn(mKeyguardStatusBarViewComponent);
         when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
                 .thenReturn(mKeyguardStatusBarViewController);
@@ -438,6 +456,8 @@
                 .thenReturn(mIdleHostViewController);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
                 .thenReturn(mKeyguardStatusView);
+        when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
+                .thenReturn(mUserSwitcherView);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
                 .thenReturn(mKeyguardBottomArea);
         when(mNotificationRemoteInputManager.isRemoteInputActive()).thenReturn(false);
@@ -448,16 +468,17 @@
                 mResources,
                 new Handler(Looper.getMainLooper()),
                 mLayoutInflater,
+                mFeatureFlags,
                 coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
                 mFalsingManager, new FalsingCollectorFake(),
                 mNotificationLockscreenUserManager, mNotificationEntryManager,
-                mKeyguardStateController, mStatusBarStateController, mDozeLog,
-                mDozeParameters, mCommandQueue, mVibratorHelper,
+                mCommunalStateController, mKeyguardStateController, mStatusBarStateController,
+                mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
                 mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
                 mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController,
                 () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
                 mConversationNotificationManager, mMediaHiearchyManager,
-                mBiometricUnlockController, mStatusBarKeyguardViewManager,
+                mStatusBarKeyguardViewManager,
                 mNotificationStackScrollLayoutController,
                 mKeyguardStatusViewComponentFactory,
                 mKeyguardQsUserSwitchComponentFactory,
@@ -487,8 +508,8 @@
                 new FakeExecutor(new FakeSystemClock()),
                 mSecureSettings,
                 mSplitShadeHeaderController,
-                mLockscreenSmartspaceController,
                 mUnlockedScreenOffAnimationController,
+                mLockscreenGestureLogger,
                 mNotificationRemoteInputManager,
                 mControlsComponent);
         mNotificationPanelViewController.initDependencies(
@@ -555,20 +576,6 @@
     }
 
     @Test
-    public void testKeyguardStatusBarVisibility_hiddenForBypass() {
-        when(mUpdateMonitor.shouldListenForFace()).thenReturn(true);
-        mNotificationPanelViewController.mKeyguardUpdateCallback.onBiometricRunningStateChanged(
-                true, BiometricSourceType.FACE);
-        verify(mKeyguardStatusBar, never()).setVisibility(View.VISIBLE);
-
-        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
-        mNotificationPanelViewController.mKeyguardUpdateCallback.onFinishedGoingToSleep(0);
-        mNotificationPanelViewController.mKeyguardUpdateCallback.onBiometricRunningStateChanged(
-                true, BiometricSourceType.FACE);
-        verify(mKeyguardStatusBar, never()).setVisibility(View.VISIBLE);
-    }
-
-    @Test
     public void testA11y_initializeNode() {
         AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
         mAccessibiltyDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
@@ -848,9 +855,10 @@
 
     @Test
     public void testCommunalhostViewControllerInit() {
+        verify(mCommunalHostViewController, times(1)).init();
         clearInvocations(mCommunalHostViewController);
         givenViewAttached();
-        verify(mCommunalHostViewController).init();
+        verify(mCommunalHostViewController, never()).init();
     }
 
     @Test
@@ -871,8 +879,52 @@
         clearInvocations(mCommunalHostViewController);
         givenViewDetached();
         verify(mCommunalSourceMonitor).removeCallback(any());
-        verify(mCommunalHostViewController).show(sourceCapture.capture());
-        assertThat(sourceCapture.getValue()).isEqualTo(null);
+    }
+
+    @Test
+    public void testKeyguardStatusViewUpdatedWithCommunalPresence() {
+        givenViewAttached();
+
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
+        updateMultiUserSetting(true);
+
+        ArgumentCaptor<CommunalStateController.Callback> communalCallbackCapture =
+                ArgumentCaptor.forClass(CommunalStateController.Callback.class);
+        verify(mCommunalStateController).addCallback(communalCallbackCapture.capture());
+        final CommunalStateController.Callback communalStateControllerCallback =
+                communalCallbackCapture.getValue();
+
+        clearInvocations(mKeyguardStatusViewController, mKeyguardUserSwitcherController);
+        // Ensure changes in communal visibility leads to setting the keyguard status view
+        // visibility.
+        communalStateControllerCallback.onCommunalViewShowingChanged();
+        verify(mKeyguardStatusViewController).setKeyguardStatusViewVisibility(anyInt(),
+                anyBoolean(), anyBoolean(), anyInt());
+        verify(mKeyguardUserSwitcherController).setKeyguardUserSwitcherVisibility(anyInt(),
+                anyBoolean(), anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void testCommunalAlphaUpdate() {
+        // Verify keyguard content alpha changes are propagate. Note the actual value set is not
+        // checked since an interpolation is applied to the incoming value.
+        mNotificationPanelViewController.setKeyguardOnlyContentAlpha(0.8f);
+        verify(mCommunalHostViewController).setAlpha(anyFloat());
+    }
+
+    @Test
+    public void testCommunalPositionUpdate() {
+        // Verify that the communal position is updated on interaction with the
+        // NotificationPanelViewController. Note that there a number of paths where the position
+        // might be updated and therefore the check isn't strictly on a single invocation.
+        clearInvocations(mCommunalHostViewController);
+        final View.OnLayoutChangeListener layoutChangeListener =
+                mNotificationPanelViewController.createLayoutChangeListener();
+        mNotificationPanelViewController.mStatusBarStateController.setState(KEYGUARD);
+        layoutChangeListener.onLayoutChange(mView, 0, 0, 200, 200, 0, 0, 200, 200);
+        verify(mCommunalHostViewController, atLeast(1))
+                .updatePosition(anyInt(), anyBoolean());
     }
 
     private void triggerPositionClockAndNotifications() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index ddd7854..90b8a74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -146,7 +146,7 @@
         mNotificationShadeWindowController.attach();
 
         clearInvocations(mWindowManager);
-        mNotificationShadeWindowController.setLightRevealScrimAmount(0f);
+        mNotificationShadeWindowController.setLightRevealScrimOpaque(true);
         verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
         assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) == 0).isTrue();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 6c1a3c9..3d887dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -16,6 +16,11 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -41,7 +46,6 @@
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -55,6 +59,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;
 
@@ -85,12 +91,16 @@
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
     @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
-    @Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
+    @Mock private StatusBarWindowView mStatusBarWindowView;
     @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
     @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
 
+    @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
+            mInteractionEventHandlerCaptor;
+    private NotificationShadeWindowView.InteractionEventHandler mInteractionEventHandler;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -129,7 +139,7 @@
                 mNotificationShadeDepthController,
                 mView,
                 mNotificationPanelViewController,
-                mStatusBarViewFactory,
+                mStatusBarWindowView,
                 mNotificationStackScrollLayoutController,
                 mStatusBarKeyguardViewManager);
         mController.setupExpandedStatusBar();
@@ -147,4 +157,49 @@
         verify(mDragDownHelper).onTouchEvent(ev);
         ev.recycle();
     }
+
+    @Test
+    public void testInterceptTouchWhenShowingAltAuth() {
+        captureInteractionEventHandler();
+
+        // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true);
+        when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
+
+        // THEN we should intercept touch
+        assertTrue(mInteractionEventHandler.shouldInterceptTouchEvent(mock(MotionEvent.class)));
+    }
+
+    @Test
+    public void testNoInterceptTouch() {
+        captureInteractionEventHandler();
+
+        // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(false);
+        when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
+
+        // THEN we shouldn't intercept touch
+        assertFalse(mInteractionEventHandler.shouldInterceptTouchEvent(mock(MotionEvent.class)));
+    }
+
+    @Test
+    public void testHandleTouchEventWhenShowingAltAuth() {
+        captureInteractionEventHandler();
+
+        // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true);
+        when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false);
+
+        // THEN we should handle the touch
+        assertTrue(mInteractionEventHandler.handleTouchEvent(mock(MotionEvent.class)));
+    }
+
+    private void captureInteractionEventHandler() {
+        verify(mView).setInteractionEventHandler(mInteractionEventHandlerCaptor.capture());
+        mInteractionEventHandler = mInteractionEventHandlerCaptor.getValue();
+
+    }
 }
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
index 50cea07..d63730d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -38,7 +38,6 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-
         view = PhoneStatusBarView(mContext, null)
         controller = PhoneStatusBarViewController(view, commandQueue)
     }
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 30fc13b..5ebe900 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
@@ -16,10 +16,13 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
 import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
 import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -709,7 +712,7 @@
     public void qsExpansion_half_clippingQs() {
         reset(mScrimBehind);
         mScrimController.setClipsQsScrim(true);
-        mScrimController.setQsPosition(0.5f, 999 /* value doesn't matter */);
+        mScrimController.setQsPosition(0.25f, 999 /* value doesn't matter */);
         finishAnimationsImmediately();
 
         assertScrimAlpha(Map.of(
@@ -741,6 +744,28 @@
     }
 
     @Test
+    public void transitionToUnlockedFromOff() {
+        // Simulate unlock with fingerprint without AOD
+        mScrimController.transitionTo(ScrimState.OFF);
+        mScrimController.setPanelExpansion(0f);
+        finishAnimationsImmediately();
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+
+        finishAnimationsImmediately();
+
+        // All scrims should be transparent at the end of fade transition.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+
+        // Make sure at the very end of the animation, we're reset to transparent
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, true
+        ));
+    }
+
+    @Test
     public void transitionToUnlockedFromAod() {
         // Simulate unlock with fingerprint
         mScrimController.transitionTo(ScrimState.AOD);
@@ -748,12 +773,6 @@
         finishAnimationsImmediately();
         mScrimController.transitionTo(ScrimState.UNLOCKED);
 
-        // Immediately tinted black after the transition starts
-        assertScrimTinted(Map.of(
-                mScrimInFront, true,
-                mScrimBehind, true
-        ));
-
         finishAnimationsImmediately();
 
         // All scrims should be transparent at the end of fade transition.
@@ -1082,6 +1101,26 @@
     }
 
     @Test
+    public void testDoesntAnimate_whenUnlocking() {
+        // LightRevealScrim will animate the transition, we should only hide the keyguard scrims.
+        ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+        assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+        ScrimState.UNLOCKED.prepare(ScrimState.PULSING);
+        assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
+
+        ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+        assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+        ScrimState.UNLOCKED.prepare(ScrimState.AOD);
+        assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
+
+        // LightRevealScrim doesn't animate when AOD is disabled. We need to use the legacy anim.
+        ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+        assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+        ScrimState.UNLOCKED.prepare(ScrimState.OFF);
+        assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+    }
+
+    @Test
     public void testScrimsVisible_whenShadeVisible_clippingQs() {
         mScrimController.setClipsQsScrim(true);
         mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -1099,7 +1138,7 @@
     @Test
     public void testScrimsVisible_whenShadeVisibleOnLockscreen() {
         mScrimController.transitionTo(ScrimState.KEYGUARD);
-        mScrimController.setQsPosition(0.5f, 300);
+        mScrimController.setQsPosition(0.25f, 300);
 
         assertScrimAlpha(Map.of(
                 mScrimBehind, SEMI_TRANSPARENT,
@@ -1139,6 +1178,21 @@
     }
 
     @Test
+    public void testNotificationTransparency_unnocclusion() {
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        mScrimController.setUnocclusionAnimationRunning(true);
+
+        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
+                /* expansion */ 0.0f);
+        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
+                /* expansion */ 1.0f);
+
+        // Verify normal behavior after
+        mScrimController.setUnocclusionAnimationRunning(false);
+        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.4f);
+    }
+
+    @Test
     public void testNotificationTransparency_inKeyguardState() {
         mScrimController.transitionTo(ScrimState.KEYGUARD);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index 10eb71f..1503af8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -16,32 +16,54 @@
 
 package com.android.systemui.statusbar.phone
 
+import android.content.Context
+import android.content.res.Configuration
 import android.graphics.Rect
 import android.test.suitebuilder.annotation.SmallTest
+import android.view.Display
 import android.view.DisplayCutout
-import android.view.WindowMetrics
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.leak.RotationUtils
 import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
 import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
 import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
 import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
 import com.android.systemui.util.leak.RotationUtils.Rotation
+import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
+import org.mockito.ArgumentMatchers.any
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
 import org.mockito.MockitoAnnotations
 
 @SmallTest
 class StatusBarContentInsetsProviderTest : SysuiTestCase() {
+
     @Mock private lateinit var dc: DisplayCutout
-    @Mock private lateinit var windowMetrics: WindowMetrics
+    @Mock private lateinit var contextMock: Context
+    @Mock private lateinit var display: Display
+    private lateinit var configurationController: ConfigurationController
+
+    private val configuration = Configuration()
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
+        `when`(contextMock.display).thenReturn(display)
+
+        context.ensureTestableResources()
+        `when`(contextMock.resources).thenReturn(context.resources)
+        `when`(contextMock.resources.configuration).thenReturn(configuration)
+        `when`(contextMock.createConfigurationContext(any())).thenAnswer {
+            context.createConfigurationContext(it.arguments[0] as Configuration)
+        }
+
+        configurationController = ConfigurationControllerImpl(contextMock)
     }
 
     @Test
@@ -55,15 +77,13 @@
         val chipWidth = 30
         val dotWidth = 10
 
-        `when`(windowMetrics.bounds).thenReturn(screenBounds)
-
         var isRtl = false
         var targetRotation = ROTATION_NONE
         var bounds = calculateInsetsForRotationWithRotatedResources(
                 currentRotation,
                 targetRotation,
                 null,
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -92,7 +112,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -127,7 +147,6 @@
         val sbHeightLandscape = 60
         val currentRotation = ROTATION_NONE
 
-        `when`(windowMetrics.bounds).thenReturn(screenBounds)
         `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
 
         // THEN rotations which share a short side should use the greater value between rounded
@@ -142,7 +161,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -159,7 +178,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -178,7 +197,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -196,7 +215,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -219,7 +238,6 @@
         val sbHeightLandscape = 60
         val currentRotation = ROTATION_NONE
 
-        `when`(windowMetrics.bounds).thenReturn(screenBounds)
         `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
 
         // THEN only the landscape/seascape rotations should avoid the cutout area because of the
@@ -234,7 +252,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -251,7 +269,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -268,7 +286,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -285,7 +303,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -303,8 +321,6 @@
         val sbHeightPortrait = 100
         val sbHeightLandscape = 60
 
-        `when`(windowMetrics.bounds).thenReturn(screenBounds)
-
         // THEN content insets should only use rounded corner padding
         var targetRotation = ROTATION_NONE
         var expectedBounds = Rect(minLeftPadding,
@@ -316,7 +332,7 @@
                 currentRotation,
                 targetRotation,
                 null, /* no cutout */
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -332,7 +348,7 @@
                 currentRotation,
                 targetRotation,
                 null, /* no cutout */
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -348,7 +364,7 @@
                 currentRotation,
                 targetRotation,
                 null, /* no cutout */
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -364,7 +380,7 @@
                 currentRotation,
                 targetRotation,
                 null, /* no cutout */
-                windowMetrics,
+                screenBounds,
                 sbHeightLandscape,
                 minLeftPadding,
                 minRightPadding)
@@ -382,7 +398,6 @@
         val sbHeightLandscape = 60
         val currentRotation = ROTATION_NONE
 
-        `when`(windowMetrics.bounds).thenReturn(screenBounds)
         `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
 
         // THEN left should be set to the display cutout width, and right should use the minRight
@@ -396,7 +411,7 @@
                 currentRotation,
                 targetRotation,
                 dc,
-                windowMetrics,
+                screenBounds,
                 sbHeightPortrait,
                 minLeftPadding,
                 minRightPadding)
@@ -404,6 +419,67 @@
         assertRects(expectedBounds, bounds, currentRotation, targetRotation)
     }
 
+    @Test
+    fun testDisplayChanged_returnsUpdatedInsets() {
+        // GIVEN: get insets on the first display and switch to the second display
+        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
+            mock(DumpManager::class.java))
+
+        givenDisplay(
+            screenBounds = Rect(0, 0, 1080, 2160),
+            displayUniqueId = "1"
+        )
+        val firstDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+        givenDisplay(
+            screenBounds = Rect(0, 0, 800, 600),
+            displayUniqueId = "2"
+        )
+        configurationController.onConfigurationChanged(configuration)
+
+        // WHEN: get insets on the second display
+        val secondDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+
+        // THEN: insets are updated
+        assertThat(firstDisplayInsets).isNotEqualTo(secondDisplayInsets)
+    }
+
+    @Test
+    fun testDisplayChangedAndReturnedBack_returnsTheSameInsets() {
+        // GIVEN: get insets on the first display, switch to the second display,
+        // get insets and switch back
+        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
+            mock(DumpManager::class.java))
+        givenDisplay(
+            screenBounds = Rect(0, 0, 1080, 2160),
+            displayUniqueId = "1"
+        )
+        val firstDisplayInsetsFirstCall = provider
+            .getStatusBarContentInsetsForRotation(ROTATION_NONE)
+        givenDisplay(
+            screenBounds = Rect(0, 0, 800, 600),
+            displayUniqueId = "2"
+        )
+        configurationController.onConfigurationChanged(configuration)
+        provider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+        givenDisplay(
+            screenBounds = Rect(0, 0, 1080, 2160),
+            displayUniqueId = "1"
+        )
+        configurationController.onConfigurationChanged(configuration)
+
+        // WHEN: get insets on the first display again
+        val firstDisplayInsetsSecondCall = provider
+            .getStatusBarContentInsetsForRotation(ROTATION_NONE)
+
+        // THEN: insets for the first and second calls for the first display are the same
+        assertThat(firstDisplayInsetsFirstCall).isEqualTo(firstDisplayInsetsSecondCall)
+    }
+
+    private fun givenDisplay(screenBounds: Rect, displayUniqueId: String) {
+        `when`(display.uniqueId).thenReturn(displayUniqueId)
+        configuration.windowConfiguration.maxBounds = screenBounds
+    }
+
     private fun assertRects(
         expected: Rect,
         actual: Rect,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index c39a906..38f36bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -64,6 +64,8 @@
 
 import java.util.Optional;
 
+import dagger.Lazy;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -103,6 +105,8 @@
     private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
     @Mock
     private KeyguardMessageArea mKeyguardMessageArea;
+    @Mock
+    private Lazy<ShadeController> mShadeController;
 
     private WakefulnessLifecycle mWakefulnessLifecycle;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -133,7 +137,8 @@
                 mKeyguardBouncerFactory,
                 mWakefulnessLifecycle,
                 mUnlockedScreenOffAnimationController,
-                mKeyguardMessageAreaFactory);
+                mKeyguardMessageAreaFactory,
+                mShadeController);
         mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
                 mNotificationPanelView, mBiometrucUnlockController,
                 mNotificationContainer, mBypassController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index fd85c44..c80c072 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -31,9 +31,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.ForegroundServiceNotificationListener;
 import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,6 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -59,6 +58,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
@@ -66,14 +66,10 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
-import java.util.ArrayList;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper()
 public class StatusBarNotificationPresenterTest extends SysuiTestCase {
-
-
     private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
     private NotificationInterruptStateProvider mNotificationInterruptStateProvider =
             mock(NotificationInterruptStateProvider.class);
@@ -86,27 +82,16 @@
 
     @Before
     public void setup() {
-        NotificationRemoteInputManager notificationRemoteInputManager =
-                mock(NotificationRemoteInputManager.class);
         mMetricsLogger = new FakeMetricsLogger();
-        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+        LockscreenGestureLogger lockscreenGestureLogger = new LockscreenGestureLogger(
+                mMetricsLogger);
         mCommandQueue = new CommandQueue(mContext);
         mDependency.injectTestDependency(StatusBarStateController.class,
                 mock(SysuiStatusBarStateController.class));
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
-        mDependency.injectTestDependency(NotificationRemoteInputManager.class,
-                notificationRemoteInputManager);
-        mDependency.injectMockDependency(NotificationViewHierarchyManager.class);
         mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
-        mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
-        mDependency.injectMockDependency(NotificationMediaManager.class);
-        mDependency.injectMockDependency(VisualStabilityManager.class);
-        mDependency.injectMockDependency(NotificationGutsManager.class);
         mDependency.injectMockDependency(NotificationShadeWindowController.class);
         mDependency.injectMockDependency(ForegroundServiceNotificationListener.class);
-        NotificationEntryManager entryManager =
-                mDependency.injectMockDependency(NotificationEntryManager.class);
-        when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
 
         NotificationShadeWindowView notificationShadeWindowView =
                 mock(NotificationShadeWindowView.class);
@@ -126,8 +111,19 @@
                 mock(KeyguardStateController.class),
                 mock(KeyguardIndicationController.class), mStatusBar,
                 mock(ShadeControllerImpl.class), mock(LockscreenShadeTransitionController.class),
-                mCommandQueue, mInitController,
-                mNotificationInterruptStateProvider);
+                mCommandQueue,
+                mock(NotificationViewHierarchyManager.class),
+                mock(NotificationLockscreenUserManager.class),
+                mock(SysuiStatusBarStateController.class),
+                mock(NotificationEntryManager.class),
+                mock(NotificationMediaManager.class),
+                mock(NotificationGutsManager.class),
+                mock(KeyguardUpdateMonitor.class),
+                lockscreenGestureLogger,
+                mInitController,
+                mNotificationInterruptStateProvider,
+                mock(NotificationRemoteInputManager.class),
+                mock(ConfigurationController.class));
         mInitController.executePostInitTasks();
         ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
                 ArgumentCaptor.forClass(NotificationInterruptSuppressor.class);
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 c06a9ae..2f7e39b3 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
@@ -105,10 +105,10 @@
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -137,12 +137,14 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.unfold.config.UnfoldTransitionConfig;
 import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.MessageRouterImpl;
 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;
@@ -157,8 +159,6 @@
 import java.io.PrintWriter;
 import java.util.Optional;
 
-import javax.inject.Provider;
-
 import dagger.Lazy;
 
 @SmallTest
@@ -204,6 +204,7 @@
     @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private AssistManager mAssistManager;
+    @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationMediaManager mNotificationMediaManager;
     @Mock private NavigationBarController mNavigationBarController;
@@ -225,17 +226,17 @@
     @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
     @Mock private DozeParameters mDozeParameters;
     @Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
+    @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
     @Mock private LockscreenWallpaper mLockscreenWallpaper;
     @Mock private DozeServiceHost mDozeServiceHost;
     @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
     @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
-    @Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
-    @Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
+    @Mock private StatusBarComponent.Factory mStatusBarComponentFactory;
     @Mock private StatusBarComponent mStatusBarComponent;
     @Mock private PluginManager mPluginManager;
     @Mock private LegacySplitScreen mLegacySplitScreen;
-    @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    @Mock private StatusBarWindowView mStatusBarWindowView;
     @Mock private LightsOutNotifController mLightsOutNotifController;
     @Mock private ViewMediatorCallback mViewMediatorCallback;
     @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@@ -262,9 +263,14 @@
     @Mock private IWallpaperManager mIWallpaperManager;
     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock private TunerService mTunerService;
     @Mock private StartingSurface mStartingSurface;
+    @Mock private OperatorNameViewController mOperatorNameViewController;
+    @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
     private ShadeController mShadeController;
-    private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+    private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+    private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
+    private FakeExecutor mUiBgExecutor = new FakeExecutor(mFakeSystemClock);
     private InitController mInitController = new InitController();
 
     @Before
@@ -331,8 +337,7 @@
         when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper);
         when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
 
-        when(mStatusBarComponentBuilderProvider.get()).thenReturn(mStatusBarComponentBuilder);
-        when(mStatusBarComponentBuilder.build()).thenReturn(mStatusBarComponent);
+        when(mStatusBarComponentFactory.create()).thenReturn(mStatusBarComponent);
         when(mStatusBarComponent.getNotificationShadeWindowViewController()).thenReturn(
                 mNotificationShadeWindowViewController);
 
@@ -341,6 +346,9 @@
                 mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
                 () -> Optional.of(mStatusBar), () -> mAssistManager, Optional.of(mBubbles));
 
+        when(mOperatorNameViewControllerFactory.create(any()))
+                .thenReturn(mOperatorNameViewController);
+
         mStatusBar = new StatusBar(
                 mContext,
                 mNotificationsController,
@@ -357,6 +365,7 @@
                 new FalsingManagerFake(),
                 new FalsingCollectorFake(),
                 mBroadcastDispatcher,
+                mNotificationEntryManager,
                 mNotificationGutsManager,
                 notificationLogger,
                 mNotificationInterruptStateProvider,
@@ -386,19 +395,20 @@
                 mDozeParameters,
                 mScrimController,
                 mLockscreenWallpaperLazy,
+                mLockscreenGestureLogger,
                 mBiometricUnlockControllerLazy,
                 mDozeServiceHost,
                 mPowerManager, mScreenPinningRequest,
                 mDozeScrimController,
                 mVolumeComponent,
                 mCommandQueue,
-                mStatusBarComponentBuilderProvider,
+                mStatusBarComponentFactory,
                 mPluginManager,
                 Optional.of(mLegacySplitScreen),
                 mLightsOutNotifController,
                 mStatusBarNotificationActivityStarterBuilder,
                 mShadeController,
-                mSuperStatusBarViewFactory,
+                mStatusBarWindowView,
                 mStatusBarKeyguardViewManager,
                 mViewMediatorCallback,
                 mInitController,
@@ -407,6 +417,7 @@
                 mKeyguardDismissUtil,
                 mExtensionController,
                 mUserInfoControllerImpl,
+                mOperatorNameViewControllerFactory,
                 mPhoneStatusBarPolicy,
                 mKeyguardIndicationController,
                 mDemoModeController,
@@ -423,9 +434,13 @@
                 mLockscreenTransitionController,
                 mFeatureFlags,
                 mKeyguardUnlockAnimationController,
+                new Handler(TestableLooper.get(this).getLooper()),
+                mMainExecutor,
+                new MessageRouterImpl(mMainExecutor),
                 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)))
@@ -688,7 +703,7 @@
         } catch (RemoteException e) {
             fail();
         }
-        TestableLooper.get(this).processAllMessages();
+        mMainExecutor.runAllReady();
     }
 
     @Test
@@ -707,7 +722,7 @@
         } catch (RemoteException e) {
             fail();
         }
-        TestableLooper.get(this).processAllMessages();
+        mMainExecutor.runAllReady();
     }
 
     @Test
@@ -725,7 +740,7 @@
         } catch (RemoteException e) {
             fail();
         }
-        TestableLooper.get(this).processAllMessages();
+        mMainExecutor.runAllReady();
     }
 
     @Test
@@ -740,15 +755,6 @@
     }
 
     @Test
-    @RunWithLooper(setAsMainLooper = true)
-    public void testUpdateKeyguardState_DoesNotCrash() {
-        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
-        when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(
-                new SparseArray<>());
-        mStatusBar.onStateChanged(StatusBarState.SHADE);
-    }
-
-    @Test
     public void testFingerprintNotification_UpdatesScrims() {
         mStatusBar.notifyBiometricAuthModeChanged();
         verify(mScrimController).transitionTo(any(), any());
@@ -764,6 +770,30 @@
     }
 
     @Test
+    public void testTransitionLaunch_goesToUnlocked() {
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+        mStatusBar.showKeyguardImpl();
+
+        // Starting a pulse should change the scrim controller to the pulsing state
+        when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true);
+        when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(true);
+        mStatusBar.updateScrimController();
+        verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
+    }
+
+    @Test
+    public void testTransitionLaunch_noPreview_doesntGoUnlocked() {
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+        mStatusBar.showKeyguardImpl();
+
+        // Starting a pulse should change the scrim controller to the pulsing state
+        when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true);
+        when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(false);
+        mStatusBar.updateScrimController();
+        verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD));
+    }
+
+    @Test
     public void testSetOccluded_propagatesToScrimController() {
         mStatusBar.setOccluded(true);
         verify(mScrimController).setKeyguardOccluded(eq(true));
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 31fa04d..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
@@ -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.
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 21c4a17..c488ee9 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,6 +70,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
@@ -241,7 +242,9 @@
                 mMockBd,
                 mDemoModeController,
                 mCarrierConfigTracker,
-                mFeatureFlags);
+                mFeatureFlags,
+                mock(DumpManager.class)
+        );
         setupNetworkController();
 
         // Trigger blank callbacks to always get the current state (some tests don't trigger
@@ -309,7 +312,8 @@
                         mock(AccessPointControllerImpl.class),
                         mock(DataUsageController.class), mMockSubDefaults,
                         mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
-                        mCarrierConfigTracker, mFeatureFlags);
+                        mCarrierConfigTracker, mFeatureFlags,
+                        mock(DumpManager.class));
 
         setupNetworkController();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index bc4c2b6..3433a14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -21,6 +21,7 @@
 
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.util.CarrierConfigTracker;
 
 import org.junit.Test;
@@ -113,7 +114,7 @@
                 mock(AccessPointControllerImpl.class),
                 mock(DataUsageController.class), mMockSubDefaults,
                 mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
-                mock(CarrierConfigTracker.class), mFeatureFlags);
+                mock(CarrierConfigTracker.class), mFeatureFlags, mock(DumpManager.class));
         setupNetworkController();
 
         setupDefaultSignal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 5090b0d..4ff1301 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -41,6 +41,7 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.util.CarrierConfigTracker;
 
 import org.junit.Test;
@@ -67,7 +68,8 @@
                 Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
-                mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags);
+                mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
+                mock(DumpManager.class));
         setupNetworkController();
 
         verifyLastMobileDataIndicators(false, -1, 0);
@@ -87,7 +89,8 @@
                 Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
-                mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags);
+                mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
+                mock(DumpManager.class));
         mNetworkController.registerListeners();
 
         // Wait for the main looper to execute the previous command
@@ -155,7 +158,8 @@
                 Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
-                mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags);
+                mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
+                mock(DumpManager.class));
         setupNetworkController();
 
         // No Subscriptions.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 57198db..4a5770d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -238,7 +238,7 @@
         mNetworkController.setNoNetworksAvailable(false);
         setWifiStateForVcn(true, testSsid);
         setWifiLevelForVcn(0);
-        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
+        verifyLastMobileDataIndicatorsForVcn(true, 0, TelephonyIcons.ICON_CWF, false);
 
         mNetworkController.setNoNetworksAvailable(true);
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
@@ -246,11 +246,11 @@
 
             setConnectivityViaCallbackInNetworkControllerForVcn(
                     NetworkCapabilities.TRANSPORT_CELLULAR, true, true, mVcnTransportInfo);
-            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
+            verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, true);
 
             setConnectivityViaCallbackInNetworkControllerForVcn(
                     NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo);
-            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
+            verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 32aee2b..ac04fa7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -581,8 +581,6 @@
         // devices.
         layout.setBaselineAligned(false);
 
-        final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-
         // Add smart replies
         Button previous = null;
         SmartReplyView.SmartReplies smartReplies =
@@ -602,11 +600,7 @@
             if (previous != null) {
                 ViewGroup.MarginLayoutParams lp =
                         (ViewGroup.MarginLayoutParams) previous.getLayoutParams();
-                if (isRtl) {
-                    lp.leftMargin = mSpacing;
-                } else {
-                    lp.rightMargin = mSpacing;
-                }
+                lp.setMarginEnd(mSpacing);
             }
             layout.addView(current);
             previous = current;
@@ -630,11 +624,7 @@
             if (previous != null) {
                 ViewGroup.MarginLayoutParams lp =
                         (ViewGroup.MarginLayoutParams) previous.getLayoutParams();
-                if (isRtl) {
-                    lp.leftMargin = mSpacing;
-                } else {
-                    lp.rightMargin = mSpacing;
-                }
+                lp.setMarginEnd(mSpacing);
             }
             layout.addView(current);
             previous = current;
@@ -933,8 +923,8 @@
                 .collect(Collectors.toList());
         Button singleLineButton = buttons.get(0);
         Button doubleLineButton = buttons.get(1);
-        Drawable singleLineDrawable = singleLineButton.getCompoundDrawables()[0]; // left drawable
-        Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawables()[0]; // left drawable
+        Drawable singleLineDrawable = singleLineButton.getCompoundDrawablesRelative()[0]; // start
+        Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawablesRelative()[0]; // start
         assertEquals(singleLineDrawable.getBounds().width(),
                      doubleLineDrawable.getBounds().width());
         assertEquals(singleLineDrawable.getBounds().height(),
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/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 9c47f19..e6dc4db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -96,6 +96,8 @@
     DumpManager mDumpManager;
     @Mock
     OverlayManagerTransaction.Builder mTransactionBuilder;
+    @Mock
+    Runnable mOnOverlaysApplied;
 
     private ThemeOverlayApplier mManager;
     private boolean mGetOverlayInfoEnabled = true;
@@ -103,7 +105,8 @@
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(),
+        mManager = new ThemeOverlayApplier(mOverlayManager,
+                MoreExecutors.directExecutor(), MoreExecutors.directExecutor(),
                 LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) {
             @Override
             protected OverlayManagerTransaction.Builder getTransactionBuilder() {
@@ -173,7 +176,7 @@
     @Test
     public void allCategoriesSpecified_allEnabledExclusively() {
         mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
-                TEST_USER_HANDLES);
+                TEST_USER_HANDLES, mOnOverlaysApplied);
         verify(mOverlayManager).commit(any());
 
         for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
@@ -185,7 +188,7 @@
     @Test
     public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
         mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
-                TEST_USER_HANDLES);
+                TEST_USER_HANDLES, mOnOverlaysApplied);
 
         for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) {
             if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
@@ -202,8 +205,9 @@
     public void allCategoriesSpecified_enabledForAllUserHandles() {
         Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
         mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
-                userHandles);
+                userHandles, mOnOverlaysApplied);
 
+        verify(mOnOverlaysApplied).run();
         for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
             verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
                     eq(TEST_USER.getIdentifier()));
@@ -219,7 +223,7 @@
 
         Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
         mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
-                userHandles);
+                userHandles, mOnOverlaysApplied);
 
         for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
             verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true),
@@ -233,7 +237,7 @@
                 mock(FabricatedOverlay.class)
         };
         mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation,
-                TEST_USER.getIdentifier(), TEST_USER_HANDLES);
+                TEST_USER.getIdentifier(), TEST_USER_HANDLES, mOnOverlaysApplied);
 
         for (FabricatedOverlay overlay : pendingCreation) {
             verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay));
@@ -247,7 +251,7 @@
         categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
 
         mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
-                TEST_USER_HANDLES);
+                TEST_USER_HANDLES, mOnOverlaysApplied);
 
         for (OverlayIdentifier overlayPackage : categoryToPackage.values()) {
             verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
@@ -264,7 +268,7 @@
     @Test
     public void zeroCategoriesSpecified_allDisabled() {
         mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(),
-                TEST_USER_HANDLES);
+                TEST_USER_HANDLES, mOnOverlaysApplied);
 
         for (String category : THEME_CATEGORIES) {
             verify(mTransactionBuilder).setEnabled(
@@ -279,7 +283,7 @@
         categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category"));
 
         mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
-                TEST_USER_HANDLES);
+                TEST_USER_HANDLES, mOnOverlaysApplied);
 
         verify(mTransactionBuilder, never()).setEnabled(
                 eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
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 f6a54936..cd911cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -161,7 +161,7 @@
                 ArgumentCaptor.forClass(Map.class);
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
 
         // Assert that we received the colors that we were expecting
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -183,7 +183,7 @@
         mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
         mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
                 null, null), WallpaperManager.FLAG_SYSTEM);
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -204,7 +204,7 @@
                 ArgumentCaptor.forClass(Map.class);
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
 
         // Assert that we received the colors that we were expecting
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -240,7 +240,7 @@
                 .isFalse();
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -270,7 +270,7 @@
                 "android.theme.customization.color_both\":\"0")).isTrue();
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -300,7 +300,7 @@
                 "android.theme.customization.color_both\":\"1")).isTrue();
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -327,7 +327,7 @@
         assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
                 .isFalse();
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -354,7 +354,7 @@
         assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
                 .isFalse();
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -382,7 +382,7 @@
                 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -411,14 +411,14 @@
 
 
         verify(mThemeOverlayApplier, never())
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
     public void onProfileAdded_setsTheme() {
         mBroadcastReceiver.getValue().onReceive(null,
                 new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -428,7 +428,7 @@
         mBroadcastReceiver.getValue().onReceive(null,
                 new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -438,7 +438,7 @@
         mBroadcastReceiver.getValue().onReceive(null,
                 new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
         verify(mThemeOverlayApplier, never())
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -450,7 +450,7 @@
                 Color.valueOf(Color.BLUE), null);
         mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
 
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
 
         // Regression test: null events should not reset the internal state and allow colors to be
         // applied again.
@@ -458,11 +458,11 @@
         mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
         mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
         verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
-                any());
+                any(), any());
         mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN),
                 null, null), WallpaperManager.FLAG_SYSTEM);
         verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
-                any());
+                any(), any());
     }
 
     @Test
@@ -499,7 +499,7 @@
         verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
 
         // Colors were applied during controller initialization.
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
         clearInvocations(mThemeOverlayApplier);
     }
 
@@ -533,7 +533,7 @@
         verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
 
         // Colors were applied during controller initialization.
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
         clearInvocations(mThemeOverlayApplier);
 
         WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
@@ -542,12 +542,12 @@
 
         // Defers event because we already have initial colors.
         verify(mThemeOverlayApplier, never())
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
 
         // Then event happens after setup phase is over.
         when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
         mDeviceProvisionedListener.getValue().onUserSetupChanged();
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -568,11 +568,11 @@
                 Color.valueOf(Color.RED), null);
         mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
         verify(mThemeOverlayApplier, never())
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
 
         mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
         verify(mThemeOverlayApplier, never())
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -592,10 +592,10 @@
                 Color.valueOf(Color.RED), null);
         mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
         verify(mThemeOverlayApplier, never())
-                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
 
         mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep();
-        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
     }
 
     @Test
@@ -614,7 +614,7 @@
                 ArgumentCaptor.forClass(Map.class);
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
 
         // Assert that we received the colors that we were expecting
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
new file mode 100644
index 0000000..eebcbe6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -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.systemui.usb
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.hardware.usb.IUsbSerialReader
+import android.hardware.usb.UsbAccessory
+import android.hardware.usb.UsbManager
+import android.testing.AndroidTestingRunner
+import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.lang.Exception
+
+/**
+ * UsbPermissionActivityTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class UsbPermissionActivityTest : SysuiTestCase() {
+
+    class UsbPermissionActivityTestable : UsbPermissionActivity()
+
+    @Rule
+    @JvmField
+    var activityRule = ActivityTestRule<UsbPermissionActivityTestable>(
+            UsbPermissionActivityTestable::class.java, false, false)
+
+    private val activityIntent = Intent(mContext, UsbPermissionActivityTestable::class.java)
+            .apply {
+                flags = Intent.FLAG_ACTIVITY_NEW_TASK
+                putExtra(UsbManager.EXTRA_PACKAGE, "com.android.systemui")
+                putExtra(Intent.EXTRA_INTENT, PendingIntent.getBroadcast(
+                        mContext,
+                        334,
+                        Intent("NO_ACTION"),
+                        PendingIntent.FLAG_MUTABLE))
+                putExtra(UsbManager.EXTRA_ACCESSORY, UsbAccessory(
+                        "manufacturer",
+                        "model",
+                        "description",
+                        "version",
+                        "uri",
+                        object : IUsbSerialReader.Stub() {
+                            override fun getSerial(packageName: String): String {
+                                return "serial"
+                            }
+                        }))
+            }
+
+    @Before
+    fun setUp() {
+        activityRule.launchActivity(activityIntent)
+    }
+
+    @After
+    fun tearDown() {
+        activityRule.finishActivity()
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun testHideNonSystemOverlay() {
+        assertThat(activityRule.activity.window.attributes.privateFlags and
+                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+                .isEqualTo(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+    }
+}
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 cc2afe2..0e9d96c 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
@@ -16,8 +16,11 @@
 
 package com.android.systemui.util.sensors;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -60,6 +63,68 @@
     }
 
     @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();
 
@@ -74,8 +139,6 @@
         mThresholdSensorPrimary.triggerEvent(false, 0);
         assertFalse(mThresholdSensorPrimary.isPaused());
         assertTrue(mThresholdSensorSecondary.isPaused());
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
     }
 
     @Test
@@ -277,30 +340,25 @@
     @Test
     public void testSecondaryCancelsSecondary() {
         TestableListener listener = new TestableListener();
-        ThresholdSensor.Listener cancelingListener = new ThresholdSensor.Listener() {
-            @Override
-            public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent event) {
-                mProximitySensor.pause();
-            }
-        };
+        ThresholdSensor.Listener cancelingListener = event -> mProximitySensor.pause();
 
         mProximitySensor.register(listener);
         mProximitySensor.register(cancelingListener);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
 
         mThresholdSensorPrimary.triggerEvent(true, 0);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
         mThresholdSensorSecondary.triggerEvent(true, 0);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isTrue();
+        assertThat(listener.mCallCount).isEqualTo(1);
 
         // The proximity sensor should now be canceled. Advancing the clock should do nothing.
-        assertEquals(0, mFakeExecutor.numPending());
+        assertThat(mFakeExecutor.numPending()).isEqualTo(0);
         mThresholdSensorSecondary.triggerEvent(false, 1);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isTrue();
+        assertThat(listener.mCallCount).isEqualTo(1);
 
         mProximitySensor.unregister(listener);
     }
@@ -311,33 +369,66 @@
 
         TestableListener listener = new TestableListener();
 
-        // WE immediately register the secondary sensor.
+        // We immediately register the secondary sensor.
         mProximitySensor.register(listener);
-        assertFalse(mThresholdSensorPrimary.isPaused());
-        assertFalse(mThresholdSensorSecondary.isPaused());
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(mThresholdSensorPrimary.isPaused()).isTrue();
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
 
         mThresholdSensorPrimary.triggerEvent(true, 0);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
+        assertThat(listener.mLastEvent).isNull();
+        assertThat(listener.mCallCount).isEqualTo(0);
         mThresholdSensorSecondary.triggerEvent(true, 0);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isTrue();
+        assertThat(listener.mCallCount).isEqualTo(1);
 
         // The secondary sensor should now remain resumed indefinitely.
-        assertFalse(mThresholdSensorSecondary.isPaused());
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
         mThresholdSensorSecondary.triggerEvent(false, 1);
-        assertFalse(listener.mLastEvent.getBelow());
-        assertEquals(2, listener.mCallCount);
+        assertThat(listener.mLastEvent.getBelow()).isFalse();
+        assertThat(listener.mCallCount).isEqualTo(2);
 
         // The secondary is still running, and not polling with the executor.
-        assertFalse(mThresholdSensorSecondary.isPaused());
-        assertEquals(0, mFakeExecutor.numPending());
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+        assertThat(mFakeExecutor.numPending()).isEqualTo(0);
 
         mProximitySensor.unregister(listener);
     }
 
+    @Test
+    public void testSecondaryPausesPrimary() {
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isFalse();
+        assertThat(mThresholdSensorSecondary.isPaused()).isTrue();
+
+        mProximitySensor.setSecondarySafe(true);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isTrue();
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+    }
+
+    @Test
+    public void testSecondaryResumesPrimary() {
+        mProximitySensor.setSecondarySafe(true);
+
+        TestableListener listener = new TestableListener();
+        mProximitySensor.register(listener);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isTrue();
+        assertThat(mThresholdSensorSecondary.isPaused()).isFalse();
+
+        mProximitySensor.setSecondarySafe(false);
+
+        assertThat(mThresholdSensorPrimary.isPaused()).isFalse();
+        assertThat(mThresholdSensorSecondary.isPaused()).isTrue();
+
+
+    }
+
     private static class TestableListener implements ThresholdSensor.Listener {
         ThresholdSensor.ThresholdSensorEvent mLastEvent;
         int mCallCount = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
index 6d1e6ce..8e1c0f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
@@ -22,7 +22,7 @@
 
 public class FakePluginManager implements PluginManager {
 
-    private final BaseLeakChecker<PluginListener> mLeakChecker;
+    private final BaseLeakChecker<PluginListener<?>> mLeakChecker;
 
     public FakePluginManager(LeakCheck test) {
         mLeakChecker = new BaseLeakChecker<>(test, "Plugin");
@@ -30,7 +30,7 @@
 
     @Override
     public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
-            Class cls, boolean allowMultiple) {
+            Class<?> cls, boolean allowMultiple) {
         mLeakChecker.addCallback(listener);
     }
 
@@ -62,17 +62,7 @@
     }
 
     @Override
-    public String[] getWhitelistedPlugins() {
+    public String[] getPrivilegedPlugins() {
         return new String[0];
     }
-
-    @Override
-    public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
-        return null;
-    }
-
-    @Override
-    public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
-        return null;
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index dd4830e..9493456 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -41,9 +41,13 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.dialog.MediaOutputDialogFactory;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.VolumeDialogController.State;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -68,23 +72,34 @@
     View mDrawerNormal;
 
     @Mock
-    VolumeDialogController mController;
-
+    VolumeDialogController mVolumeDialogController;
     @Mock
     KeyguardManager mKeyguard;
-
     @Mock
     AccessibilityManagerWrapper mAccessibilityMgr;
+    @Mock
+    DeviceProvisionedController mDeviceProvisionedController;
+    @Mock
+    ConfigurationController mConfigurationController;
+    @Mock
+    MediaOutputDialogFactory mMediaOutputDialogFactory;
+    @Mock
+    ActivityStarter mActivityStarter;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        mController = mDependency.injectMockDependency(VolumeDialogController.class);
-        mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
         getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
 
-        mDialog = new VolumeDialogImpl(getContext());
+        mDialog = new VolumeDialogImpl(
+                getContext(),
+                mVolumeDialogController,
+                mAccessibilityMgr,
+                mDeviceProvisionedController,
+                mConfigurationController,
+                mMediaOutputDialogFactory,
+                mActivityStarter);
         mDialog.init(0, null);
         State state = createShellState();
         mDialog.onStateChangedH(state);
@@ -170,7 +185,7 @@
         Mockito.reset(mAccessibilityMgr);
         ArgumentCaptor<VolumeDialogController.Callbacks> controllerCallbackCapture =
                 ArgumentCaptor.forClass(VolumeDialogController.Callbacks.class);
-        verify(mController).addCallback(controllerCallbackCapture.capture(), any());
+        verify(mVolumeDialogController).addCallback(controllerCallbackCapture.capture(), any());
         VolumeDialogController.Callbacks callbacks = controllerCallbackCapture.getValue();
         callbacks.onShowSafetyWarning(AudioManager.FLAG_SHOW_UI);
         verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
@@ -201,13 +216,13 @@
         mDialog.onStateChangedH(initialSilentState);
 
         // expected: shouldn't call vibrate yet
-        verify(mController, never()).vibrate(any());
+        verify(mVolumeDialogController, never()).vibrate(any());
 
         // changed ringer to vibrate
         mDialog.onStateChangedH(vibrateState);
 
         // expected: vibrate device
-        verify(mController).vibrate(any());
+        verify(mVolumeDialogController).vibrate(any());
     }
 
     @Test
@@ -225,7 +240,7 @@
         mDialog.onStateChangedH(vibrateState);
 
         // shouldn't call vibrate
-        verify(mController, never()).vibrate(any());
+        verify(mVolumeDialogController, never()).vibrate(any());
     }
 
     @Test
@@ -238,7 +253,7 @@
         mDrawerVibrate.performClick();
 
         // Make sure we've actually changed the ringer mode.
-        verify(mController, times(1)).setRingerMode(
+        verify(mVolumeDialogController, times(1)).setRingerMode(
                 AudioManager.RINGER_MODE_VIBRATE, false);
     }
 
@@ -252,7 +267,7 @@
         mDrawerMute.performClick();
 
         // Make sure we've actually changed the ringer mode.
-        verify(mController, times(1)).setRingerMode(
+        verify(mVolumeDialogController, times(1)).setRingerMode(
                 AudioManager.RINGER_MODE_SILENT, false);
     }
 
@@ -266,7 +281,7 @@
         mDrawerNormal.performClick();
 
         // Make sure we've actually changed the ringer mode.
-        verify(mController, times(1)).setRingerMode(
+        verify(mVolumeDialogController, times(1)).setRingerMode(
                 AudioManager.RINGER_MODE_NORMAL, false);
     }
 
diff --git a/packages/VpnDialogs/res/values-eu/strings.xml b/packages/VpnDialogs/res/values-eu/strings.xml
index 9fc16e2..a27a66a 100644
--- a/packages/VpnDialogs/res/values-eu/strings.xml
+++ b/packages/VpnDialogs/res/values-eu/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Konektatzeko eskaera"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN bidezko konexioa ezarri nahi du sareko trafikoa kontrolatzeko. Iturburua fidagarria bada bakarrik baimendu. &lt;br /&gt; &lt;br /&gt; VPN konexioa aktibo dagoenean, &lt;img src=vpn_icon /&gt; agertuko da pantailaren goialdean."</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN bidezko konexioa ezarri nahi du sareko trafikoa kontrolatzeko. Iturburua fidagarria bada bakarrik baimendu. &lt;br /&gt; &lt;br /&gt; VPN bidezko konexioa aktibo dagoenean, &lt;img src=vpn_icon /&gt; agertuko da pantailaren goialdean."</string>
     <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN bidezko konexio bat konfiguratu nahi du sareko trafikoa gainbegiratzeko. Onartu soilik iturburuaz fidatzen bazara. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; agertzen da pantailan, VPNa aktibo dagoenean."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN sarera konektatuta dago"</string>
     <string name="session" msgid="6470628549473641030">"Saioa:"</string>
diff --git a/packages/VpnDialogs/res/values-in/strings.xml b/packages/VpnDialogs/res/values-in/strings.xml
index 059008f..88a588c 100644
--- a/packages/VpnDialogs/res/values-in/strings.xml
+++ b/packages/VpnDialogs/res/values-in/strings.xml
@@ -19,19 +19,19 @@
     <string name="prompt" msgid="3183836924226407828">"Permintaan sambungan"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ingin menyiapkan sambungan VPN yang memungkinkannya memantau traffic jaringan. Terima hanya jika Anda memercayai sumber. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; muncul di bagian atas layar Anda saat VPN aktif."</string>
     <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ingin menyiapkan koneksi VPN yang memungkinkannya memantau traffic jaringan. Hanya terima jika Anda memercayai sumbernya. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; muncul di layar bila VPN aktif."</string>
-    <string name="legacy_title" msgid="192936250066580964">"VPN tersambung"</string>
+    <string name="legacy_title" msgid="192936250066580964">"VPN terhubung"</string>
     <string name="session" msgid="6470628549473641030">"Sesi:"</string>
     <string name="duration" msgid="3584782459928719435">"Durasi:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"Terkirim:"</string>
     <string name="data_received" msgid="4062776929376067820">"Diterima:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bita / <xliff:g id="NUMBER_1">%2$s</xliff:g> paket"</string>
-    <string name="always_on_disconnected_title" msgid="1906740176262776166">"Tidak dapat tersambung ke VPN yang selalu aktif"</string>
-    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> disiapkan untuk selalu tersambung, tetapi saat ini tidak dapat tersambung. Ponsel akan menggunakan jaringan publik sampai dapat tersambung ulang ke <xliff:g id="VPN_APP_1">%1$s</xliff:g>."</string>
-    <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> disiapkan untuk selalu tersambung, tetapi saat ini tidak dapat tersambung. Anda akan tersambung jika VPN dapat tersambung ulang."</string>
+    <string name="always_on_disconnected_title" msgid="1906740176262776166">"Tidak dapat terhubung ke VPN yang selalu aktif"</string>
+    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> disiapkan untuk selalu terhubung, tetapi saat ini tidak dapat terhubung. Ponsel akan menggunakan jaringan publik sampai dapat terhubung ulang ke <xliff:g id="VPN_APP_1">%1$s</xliff:g>."</string>
+    <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> disiapkan untuk selalu terhubung, tetapi saat ini tidak dapat terhubung. Anda akan terhubung jika VPN dapat terhubung ulang."</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Ubah setelan VPN"</string>
     <string name="configure" msgid="4905518375574791375">"Konfigurasikan"</string>
-    <string name="disconnect" msgid="971412338304200056">"Putuskan sambungan"</string>
+    <string name="disconnect" msgid="971412338304200056">"Putuskan koneksi"</string>
     <string name="open_app" msgid="3717639178595958667">"Buka aplikasi"</string>
     <string name="dismiss" msgid="6192859333764711227">"Tutup"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-te/strings.xml b/packages/VpnDialogs/res/values-te/strings.xml
index 2316c62..8f8ff07 100644
--- a/packages/VpnDialogs/res/values-te/strings.xml
+++ b/packages/VpnDialogs/res/values-te/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="prompt" msgid="3183836924226407828">"కనెక్షన్ అభ్యర్థన"</string>
+    <string name="prompt" msgid="3183836924226407828">"కనెక్షన్ రిక్వెస్ట్‌"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> నెట్‌వర్క్ ట్రాఫిక్‌ని పర్యవేక్షించగలగడానికి VPN కనెక్షన్‌ను సెటప్ చేయాలనుకుంటోంది. మీరు మూలాన్ని విశ్వసిస్తే మాత్రమే ఆమోదించండి. VPN సక్రియంగా ఉన్నప్పుడు మీ స్క్రీన్ ఎగువన &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; కనిపిస్తుంది."</string>
     <string name="warning" product="tv" msgid="5188957997628124947">"నెట్‌వర్క్ ట్రాఫిక్‌ను పర్యవేక్షించగలగడానికి, <xliff:g id="APP">%s</xliff:g> VPN కనెక్షన్‌ను సెటప్ చేయాలనుకుంటోంది. మీరు సోర్స్‌ను విశ్వసిస్తే మాత్రమే ఆమోదించండి. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN యాక్టివ్‌గా ఉన్నప్పుడు మీ స్క్రీన్ పై కనిపిస్తుంది."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN కనెక్ట్ చేయబడింది"</string>
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 561d079..b0893cc 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -970,14 +970,14 @@
         }
 
         @Override
-        public boolean submit(Request request, Callback callback) {
+        public int submit(Request request, Callback callback) {
             ArrayList<Request> requests = new ArrayList<>();
             requests.add(request);
             return submit(requests, callback);
         }
 
         @Override
-        public boolean submit(List<Request> requests, Callback callback) {
+        public int submit(List<Request> requests, Callback callback) {
             ArrayList<android.hardware.camera2.extension.Request> captureRequests =
                     new ArrayList<>();
             int requestId = 0;
@@ -992,11 +992,11 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to submit request due to remote exception!");
             }
-            return false;
+            return -1;
         }
 
         @Override
-        public boolean setRepeating(Request request, Callback callback) {
+        public int setRepeating(Request request, Callback callback) {
             try {
                 ArrayList<Request> requests = new ArrayList<>();
                 requests.add(request);
@@ -1007,7 +1007,7 @@
                 Log.e(TAG, "Failed to submit repeating request due to remote exception!");
             }
 
-            return false;
+            return -1;
         }
 
         @Override
diff --git a/services/Android.bp b/services/Android.bp
index a2d6beb4..82d9b3e 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -68,7 +68,6 @@
         ":services.texttospeech-sources",
         ":services.usage-sources",
         ":services.usb-sources",
-        ":services.uwb-sources",
         ":services.voiceinteraction-sources",
         ":services.wifi-sources",
     ],
@@ -122,7 +121,6 @@
         "services.texttospeech",
         "services.usage",
         "services.usb",
-        "services.uwb",
         "services.voiceinteraction",
         "services.wifi",
         "service-blobstore",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fd05c23..a9cd0ed 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3432,7 +3432,8 @@
 
             mConnectionId = service.mId;
 
-            mClient = AccessibilityInteractionClient.getInstance(mContext);
+            mClient = AccessibilityInteractionClient.getInstance(/* initializeCache= */false,
+                    mContext);
             mClient.addConnection(mConnectionId, service);
 
             //TODO: (multi-display) We need to support multiple displays.
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index 95f3560..b095e3e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -433,13 +433,28 @@
                     MotionEvent.BUTTON_PRIMARY, 1.0f, 1.0f, mLastMotionEvent.getDeviceId(), 0,
                     mLastMotionEvent.getSource(), mLastMotionEvent.getFlags());
 
-            // The only real difference between these two events is the action flag.
+            MotionEvent pressEvent = MotionEvent.obtain(downEvent);
+            pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS);
+            pressEvent.setActionButton(MotionEvent.BUTTON_PRIMARY);
+
+            MotionEvent releaseEvent = MotionEvent.obtain(downEvent);
+            releaseEvent.setAction(MotionEvent.ACTION_BUTTON_RELEASE);
+            releaseEvent.setActionButton(MotionEvent.BUTTON_PRIMARY);
+            releaseEvent.setButtonState(0);
+
             MotionEvent upEvent = MotionEvent.obtain(downEvent);
             upEvent.setAction(MotionEvent.ACTION_UP);
+            upEvent.setButtonState(0);
 
             AutoclickController.super.onMotionEvent(downEvent, downEvent, mEventPolicyFlags);
             downEvent.recycle();
 
+            AutoclickController.super.onMotionEvent(pressEvent, pressEvent, mEventPolicyFlags);
+            pressEvent.recycle();
+
+            AutoclickController.super.onMotionEvent(releaseEvent, releaseEvent, mEventPolicyFlags);
+            releaseEvent.recycle();
+
             AutoclickController.super.onMotionEvent(upEvent, upEvent, mEventPolicyFlags);
             upEvent.recycle();
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
index 5f9aaae..9801407 100644
--- a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -40,6 +40,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -47,6 +48,7 @@
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.ImageUtils;
@@ -71,6 +73,7 @@
     @VisibleForTesting
     protected static final String ACTION_DISMISS_NOTIFICATION =
             TAG + ".ACTION_DISMISS_NOTIFICATION";
+    private static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
     private static final int SEND_NOTIFICATION_DELAY_HOURS = 24;
 
     /** Current enabled accessibility services. */
@@ -179,7 +182,8 @@
         intent.setPackage(context.getPackageName())
                 .setIdentifier(serviceComponentName.flattenToShortString())
                 .putExtra(Intent.EXTRA_COMPONENT_NAME, serviceComponentName)
-                .putExtra(Intent.EXTRA_USER_ID, userId);
+                .putExtra(Intent.EXTRA_USER_ID, userId)
+                .putExtra(Intent.EXTRA_TIME, SystemClock.elapsedRealtime());
         return intent;
     }
 
@@ -214,11 +218,24 @@
             if (TextUtils.isEmpty(action) || componentName == null) {
                 return;
             }
+            final long startTimeMills = intent.getLongExtra(Intent.EXTRA_TIME, 0);
+            final long durationMills =
+                    startTimeMills > 0 ? SystemClock.elapsedRealtime() - startTimeMills : 0;
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_SYSTEM);
             if (ACTION_SEND_NOTIFICATION.equals(action)) {
-                trySendNotification(userId, componentName);
+                if (trySendNotification(userId, componentName)) {
+                    AccessibilityStatsLogUtils.logNonA11yToolServiceWarningReported(
+                            componentName.getPackageName(),
+                            AccessibilityStatsLogUtils.ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN,
+                            durationMills);
+                }
             } else if (ACTION_A11Y_SETTINGS.equals(action)) {
-                launchSettings(userId, componentName);
+                if (tryLaunchSettings(userId, componentName)) {
+                    AccessibilityStatsLogUtils.logNonA11yToolServiceWarningReported(
+                            componentName.getPackageName(),
+                            AccessibilityStatsLogUtils.ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED,
+                            durationMills);
+                }
                 mNotificationManager.cancel(componentName.flattenToShortString(),
                         NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
                 onNotificationCanceled(userId, componentName);
@@ -240,12 +257,12 @@
             }
         }
 
-        private void trySendNotification(int userId, ComponentName componentName) {
+        private boolean trySendNotification(int userId, ComponentName componentName) {
             if (!AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
-                return;
+                return false;
             }
             if (userId != mCurrentUserId) {
-                return;
+                return false;
             }
 
             List<AccessibilityServiceInfo> enabledServiceInfos = getEnabledServiceInfos();
@@ -264,23 +281,27 @@
                                 android.R.dimen.app_icon_size);
                         sendNotification(userId, componentName, displayName,
                                 ImageUtils.buildScaledBitmap(drawable, size, size));
+                        return true;
                     }
                     break;
                 }
             }
+            return false;
         }
 
-        private void launchSettings(int userId, ComponentName componentName) {
+        private boolean tryLaunchSettings(int userId, ComponentName componentName) {
             if (userId != mCurrentUserId) {
-                return;
+                return false;
             }
             final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
             intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName.flattenToShortString());
+            intent.putExtra(EXTRA_TIME_FOR_LOGGING, SystemClock.elapsedRealtime());
             final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(
                     mContext.getDisplayId()).toBundle();
             mContext.startActivityAsUser(intent, bundle, UserHandle.of(userId));
             mContext.getSystemService(StatusBarManager.class).collapsePanels();
+            return true;
         }
 
         protected void onNotificationCanceled(int userId, ComponentName componentName) {
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/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index a56b1db..c32543a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3306,11 +3306,12 @@
                 Slog.w(TAG, "Failed to retrieve app info for " + packageName
                         + " userId=" + userId, e);
             }
-            if (newAppInfo == null) {
+            if (newAppInfo == null || provider.info == null
+                    || provider.info.providerInfo == null) {
                 continue;
             }
             ApplicationInfo oldAppInfo = provider.info.providerInfo.applicationInfo;
-            if (!newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) {
+            if (oldAppInfo == null || !newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) {
                 // Overlay paths are generated against a particular version of an application.
                 // The overlays paths of a newly upgraded application are incompatible with the
                 // old version of the application.
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3540a33..a4bf52a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -454,6 +454,7 @@
                     }
                     mWaitForInlineRequest = inlineSuggestionsRequest != null;
                     mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
+                    mWaitForInlineRequest = inlineSuggestionsRequest != null;
                     maybeRequestFillFromServiceLocked();
                     viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
                 }
@@ -860,7 +861,7 @@
         if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
                 && remoteRenderService != null
                 && isViewFocusedLocked(flags)) {
-            Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
+            final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
             if (mSessionFlags.mClientSuggestionsEnabled) {
                 final int finalRequestId = requestId;
                 inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
diff --git a/services/backup/lint-baseline.xml b/services/backup/lint-baseline.xml
new file mode 100644
index 0000000..28bb937
--- /dev/null
+++ b/services/backup/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="        return Settings.Secure.getInt(mContext.getContentResolver(), SKIP_USER_FACING_PACKAGES,"
+        errorLine2="               ~~~~~~">
+        <location
+            file="frameworks/base/services/backup/java/com/android/server/backup/UserBackupManagerService.java"
+            line="3702"
+            column="16"/>
+    </issue>
+
+</issues>
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 28a40eb..44a4997 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -48,6 +48,7 @@
 import android.annotation.SuppressLint;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.role.RoleManager;
 import android.bluetooth.BluetoothAdapter;
@@ -584,12 +585,16 @@
             }
         }
 
+        /**
+        * @deprecated Use
+        * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead.
+        */
+        @Deprecated
         @Override
         public boolean hasNotificationAccess(ComponentName component) throws RemoteException {
             checkCanCallNotificationApi(component.getPackageName());
-            String setting = Settings.Secure.getString(getContext().getContentResolver(),
-                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-            return new ComponentNameSet(setting).contains(component);
+            NotificationManager nm = getContext().getSystemService(NotificationManager.class);
+            return nm.isNotificationListenerAccessGranted(component);
         }
 
         @Override
diff --git a/services/companion/lint-baseline.xml b/services/companion/lint-baseline.xml
new file mode 100644
index 0000000..03eae39
--- /dev/null
+++ b/services/companion/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
+        errorLine1="            String setting = Settings.Secure.getString(getContext().getContentResolver(),"
+        errorLine2="             ~~~~~~~~~">
+        <location
+            file="frameworks/base/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java"
+            line="590"
+            column="14"/>
+    </issue>
+
+</issues>
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 282b868..6505c20 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",
@@ -153,7 +154,7 @@
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.rebootescrow-V1-java",
-        "android.hardware.soundtrigger-V2.4-java",
+        "android.hardware.soundtrigger-V2.3-java",
         "android.hardware.power.stats-V1-java",
         "android.hidl.manager-V1.2-java",
         "capture_state_listener-aidl-java",
@@ -206,10 +207,3 @@
     name: "protolog.conf.json.gz",
     src: ":services.core.json.gz",
 }
-
-filegroup {
-    name: "services.core-sources-deviceconfig-interface",
-    srcs: [
-        "java/com/android/server/utils/DeviceConfigInterface.java",
-    ],
-}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 0621d0f..c3bf03c 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.content.ComponentName;
@@ -48,6 +49,8 @@
 import com.android.server.pm.PackageList;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.PackageState;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -353,6 +356,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)
      */
@@ -473,6 +482,35 @@
             @AppIdInt int recipientAppId, int visibleUid,
             boolean direct);
 
+    /**
+     * Grants implicit access based on an interaction between two apps. This grants access to the
+     * from one application to the other's package metadata.
+     * <p>
+     * When an application explicitly tries to interact with another application [via an
+     * activity, service or provider that is either declared in the caller's
+     * manifest via the {@code <queries>} tag or has been exposed via the target apps manifest using
+     * the {@code visibleToInstantApp} attribute], the target application must be able to see
+     * metadata about the calling app. If the calling application uses an implicit intent [ie
+     * action VIEW, category BROWSABLE], it remains hidden from the launched app.
+     * <p>
+     * If an interaction is not explicit, the {@code direct} argument should be set to false as
+     * visibility should not be granted in some cases. This method handles that logic.
+     * <p>
+     * @param userId the user
+     * @param intent the intent that triggered the grant
+     * @param recipientAppId The app ID of the application that is being given access to {@code
+     *                       visibleUid}
+     * @param visibleUid The uid of the application that is becoming accessible to {@code
+     *                   recipientAppId}
+     * @param direct true if the access is being made due to direct interaction between visibleUid
+     *               and recipientAppId.
+     * @param retainOnUpdate true if the implicit access is retained across package update.
+     */
+    public abstract void grantImplicitAccess(
+            @UserIdInt int userId, Intent intent,
+            @AppIdInt int recipientAppId, int visibleUid,
+            boolean direct, boolean retainOnUpdate);
+
     public abstract boolean isInstantAppInstallerComponent(ComponentName component);
     /**
      * Prunes instant apps and state associated with uninstalled
@@ -613,7 +651,15 @@
      */
     public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName);
 
-    public abstract @Nullable PackageSetting getPackageSetting(String packageName);
+    /**
+     * Returns the {@link SystemApi} variant of a package for use with mainline.
+     */
+    @Nullable
+    public abstract AndroidPackageApi getAndroidPackage(@NonNull String packageName);
+
+    public abstract @Nullable PackageSetting getPackageSetting(@NonNull String packageName);
+
+    public abstract @Nullable PackageState getPackageState(@NonNull String packageName);
 
     /**
      * Returns a package for the given UID. If the UID is part of a shared user ID, one
@@ -839,6 +885,17 @@
     public abstract void forEachPackageSetting(Consumer<PackageSetting> actionLocked);
 
     /**
+     * Perform the given action for each package.
+     *
+     * @param locked whether to hold the packages lock. If the lock is not held, the objects will
+     *               be iterated using a temporary data structure. In the vast majority of cases,
+     *               the lock should not have to be held. This is exposed to mirror the
+     *               functionality of the other forEach methods, for eventual migration.
+     * @param action action to be performed
+     */
+    public abstract void forEachPackageState(boolean locked, Consumer<PackageState> action);
+
+    /**
      * Perform the given action for each installed package for a user.
      * Note that packages lock will be held while performing the actions.
      */
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 31061190b..608cbf2 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -25,9 +25,9 @@
 import static android.os.UserHandle.USER_SYSTEM;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
-import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -93,7 +93,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Locale;
@@ -804,35 +803,6 @@
         return mIsHearingAidProfileSupported;
     }
 
-    @Override
-    /** @hide */
-    public java.util.List<String> getSystemConfigEnabledProfilesForPackage(String packageName) {
-        if (Binder.getCallingUid() != Process.BLUETOOTH_UID) {
-            Slog.w(TAG, "getSystemConfigEnabledProfilesForPackage(): not allowed for non-bluetooth");
-            return null;
-        }
-
-        SystemConfig systemConfig = SystemConfig.getInstance();
-        if (systemConfig == null) {
-            return null;
-        }
-
-        android.util.ArrayMap<String, Boolean> componentEnabledStates =
-                systemConfig.getComponentsEnabledStates(packageName);
-        if (componentEnabledStates == null) {
-            return null;
-        }
-
-        ArrayList enabledProfiles = new ArrayList<String>();
-        for (Map.Entry<String, Boolean> entry : componentEnabledStates.entrySet()) {
-            if (entry.getValue()) {
-                enabledProfiles.add(entry.getKey());
-            }
-        }
-
-        return enabledProfiles;
-    }
-
     private boolean isDeviceProvisioned() {
         return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED,
                 0) != 0;
@@ -2483,7 +2453,8 @@
         try {
             foregroundUser = ActivityManager.getCurrentUser();
             valid = (callingUser == foregroundUser) || parentUser == foregroundUser
-                    || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid;
+                    || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid
+                    || callingAppId == Process.SHELL_UID;
             if (DBG && !valid) {
                 Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser="
                         + callingUser + " parentUser=" + parentUser + " foregroundUser="
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/PermissionThread.java b/services/core/java/com/android/server/PermissionThread.java
deleted file mode 100644
index cf444fa..0000000
--- a/services/core/java/com/android/server/PermissionThread.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.server;
-
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.Looper;
-import android.os.Trace;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.ServiceThread;
-
-import java.util.concurrent.Executor;
-
-/**
- * Shared singleton thread for the system. This is a thread for handling
- * calls to and from the PermissionController and handling synchronization
- * between permissions and appops states.
- */
-public final class PermissionThread extends ServiceThread {
-    private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
-    private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
-
-    private static final Object sLock = new Object();
-
-    @GuardedBy("sLock")
-    private static PermissionThread sInstance;
-    private static Handler sHandler;
-    private static HandlerExecutor sHandlerExecutor;
-
-    private PermissionThread() {
-        super("android.perm", android.os.Process.THREAD_PRIORITY_DEFAULT, /* allowIo= */ true);
-    }
-
-    private static void ensureThreadLocked() {
-        if (sInstance != null) {
-            return;
-        }
-
-        sInstance = new PermissionThread();
-        sInstance.start();
-        final Looper looper = sInstance.getLooper();
-        looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
-        looper.setSlowLogThresholdMs(
-                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
-        sHandler = new Handler(sInstance.getLooper());
-        sHandlerExecutor = new HandlerExecutor(sHandler);
-    }
-
-    public static PermissionThread get() {
-        synchronized (sLock) {
-            ensureThreadLocked();
-            return sInstance;
-        }
-    }
-
-    public static Handler getHandler() {
-        synchronized (sLock) {
-            ensureThreadLocked();
-            return sHandler;
-        }
-    }
-
-    public static Executor getExecutor() {
-        synchronized (sLock) {
-            ensureThreadLocked();
-            return sHandlerExecutor;
-        }
-    }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 7d7a410..3a03573 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -413,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,
@@ -421,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
@@ -1020,7 +1021,15 @@
                 }
             }
 
-            return upgradeAndInit(version, map);
+            try {
+                return upgradeAndInit(version, map);
+            } catch (Exception e) {
+                Log.wtf(TAG, "Failed to upgrade and set sensor privacy state,"
+                        + " resetting to default.", e);
+                mEnabled = new SparseBooleanArray();
+                mIndividualEnabled = new SparseArray<>();
+                return true;
+            }
         }
 
         private boolean upgradeAndInit(int version, SparseArray map) {
@@ -1036,22 +1045,22 @@
             final int[] users = getLocalService(UserManagerInternal.class).getUserIds();
             if (version == 0) {
                 final boolean enabled = (boolean) map.get(VER0_ENABLED);
-                final SparseBooleanArray individualEnabled =
-                        (SparseBooleanArray) map.get(VER0_INDIVIDUAL_ENABLED);
+                final SparseArray<SensorState> individualEnabled =
+                        (SparseArray<SensorState>) map.get(VER0_INDIVIDUAL_ENABLED);
 
                 final SparseBooleanArray perUserEnabled = new SparseBooleanArray();
-                final SparseArray<SparseBooleanArray> perUserIndividualEnabled =
+                final SparseArray<SparseArray<SensorState>> perUserIndividualEnabled =
                         new SparseArray<>();
 
                 // Copy global state to each user
                 for (int i = 0; i < users.length; i++) {
                     int user = users[i];
                     perUserEnabled.put(user, enabled);
-                    SparseBooleanArray userIndividualSensorEnabled = new SparseBooleanArray();
+                    SparseArray<SensorState> userIndividualSensorEnabled = new SparseArray<>();
                     perUserIndividualEnabled.put(user, userIndividualSensorEnabled);
                     for (int j = 0; j < individualEnabled.size(); j++) {
                         final int sensor = individualEnabled.keyAt(j);
-                        final boolean isSensorEnabled = individualEnabled.valueAt(j);
+                        final SensorState isSensorEnabled = individualEnabled.valueAt(j);
                         userIndividualSensorEnabled.put(sensor, isSensorEnabled);
                     }
                 }
@@ -1241,6 +1250,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;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b9de1018..3510501 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3386,8 +3386,12 @@
                     mInstaller.tryMountDataMirror(volumeUuid);
                 }
             }
-        } catch (Exception e) {
+        } catch (RemoteException | Installer.InstallerException e) {
             Slog.wtf(TAG, e);
+            // Make sure to re-throw this exception; we must not ignore failure
+            // to prepare the user storage as it could indicate that encryption
+            // wasn't successfully set up.
+            throw new RuntimeException(e);
         }
     }
 
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 9e8b9c6..3288ca8 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -23,21 +23,6 @@
             "file_patterns": ["NotificationManagerService\\.java"]
         },
         {
-            "name": "CtsContentTestCases",
-            "options": [
-                {
-                    "include-filter": "android.content.cts.ClipboardManagerTest"
-                },
-                {
-                    "include-filter": "android.content.cts.ClipDataTest"
-                },
-                {
-                    "include-filter": "android.content.cts.ClipDescriptionTest"
-                }
-            ],
-            "file_patterns": ["ClipboardService\\.java"]
-        },
-        {
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {
@@ -59,6 +44,21 @@
         {
             "name": "CtsScopedStorageDeviceOnlyTest",
             "file_patterns": ["StorageManagerService\\.java"]
+        },
+        {
+            "name": "CtsContentTestCases",
+            "options": [
+                {
+                    "include-filter": "android.content.cts.ClipboardManagerTest"
+                },
+                {
+                    "include-filter": "android.content.cts.ClipDataTest"
+                },
+                {
+                    "include-filter": "android.content.cts.ClipDescriptionTest"
+                }
+            ],
+            "file_patterns": ["ClipboardService\\.java"]
         }
     ]
 }
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/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 45e6f1ec..baf5af5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -153,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;
@@ -165,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;
 
@@ -174,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;
@@ -328,14 +329,25 @@
     };
 
     /**
-     * Watch for apps being put into forced app standby, so we can step their fg
+     * Reference to the AppStateTracker service. No lock is needed as we'll assign with the same
+     * instance to it always.
+     */
+    AppStateTracker mAppStateTracker;
+
+    /**
+     * Watch for apps being put into background restricted, so we can step their fg
      * services down.
      */
-    class ForcedStandbyListener implements AppStateTracker.ServiceStateListener {
+    class BackgroundRestrictedListener implements AppStateTracker.BackgroundRestrictedAppListener {
         @Override
-        public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
+        public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+                boolean restricted) {
             synchronized (mAm) {
-                stopAllForegroundServicesLocked(uid, packageName);
+                if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)) {
+                    stopAllForegroundServicesLocked(uid, packageName);
+                }
+                mAm.mProcessList.updateBackgroundRestrictedForUidPackageLocked(
+                        uid, packageName, restricted);
             }
         }
     }
@@ -520,12 +532,18 @@
     }
 
     void systemServicesReady() {
-        AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
-        ast.addServiceStateListener(new ForcedStandbyListener());
+        getAppStateTracker().addBackgroundRestrictedAppListener(new BackgroundRestrictedListener());
         mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
         setAllowListWhileInUsePermissionInFgs();
     }
 
+    private AppStateTracker getAppStateTracker() {
+        if (mAppStateTracker == null) {
+            mAppStateTracker = LocalServices.getService(AppStateTracker.class);
+        }
+        return mAppStateTracker;
+    }
+
     private void setAllowListWhileInUsePermissionInFgs() {
         final String attentionServicePackageName =
                 mAm.mContext.getPackageManager().getAttentionServicePackageName();
@@ -604,9 +622,22 @@
     }
 
     private boolean appRestrictedAnyInBackground(final int uid, final String packageName) {
-        final int mode = mAm.getAppOpsManager().checkOpNoThrow(
-                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
-        return (mode != AppOpsManager.MODE_ALLOWED);
+        final AppStateTracker appStateTracker = getAppStateTracker();
+        if (appStateTracker != null) {
+            return appStateTracker.isAppBackgroundRestricted(uid, packageName);
+        }
+        return false;
+    }
+
+    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,
@@ -785,8 +816,19 @@
             return null;
         }
 
-        return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
+        // If what the client try to start/connect was an alias, then we need to return the
+        // alias component name to the client, not the "target" component name, which is
+        // what realResult contains.
+        final ComponentName realResult =
+                startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
                 allowBackgroundActivityStarts, backgroundActivityStartsToken);
+        if (res.aliasComponent != null
+                && !realResult.getPackageName().startsWith("!")
+                && !realResult.getPackageName().startsWith("?")) {
+            return res.aliasComponent;
+        } else {
+            return realResult;
+        }
     }
 
     private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
@@ -807,10 +849,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,
@@ -1082,9 +1126,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;
 
@@ -1144,8 +1190,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;
 
@@ -1320,8 +1368,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();
@@ -1440,7 +1490,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<>();
                             }
@@ -1658,8 +1709,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);
     }
 
     /**
@@ -1753,8 +1834,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);
@@ -1877,10 +1957,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;
@@ -1915,10 +1997,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) {
@@ -1960,10 +2044,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),
@@ -2738,10 +2824,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);
+                        }
                     }
                 }
             }
@@ -2761,7 +2849,7 @@
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
             ConnectionRecord c = new ConnectionRecord(b, activity,
                     connection, flags, clientLabel, clientIntent,
-                    callerApp.uid, callerApp.processName, callingPackage);
+                    callerApp.uid, callerApp.processName, callingPackage, res.aliasComponent);
 
             IBinder binder = connection.asBinder();
             s.addConnection(binder, c);
@@ -2838,8 +2926,13 @@
             if (s.app != null && b.intent.received) {
                 // Service is already running, so we can immediately
                 // publish the connection.
+
+                // If what the client try to start/connect was an alias, then we need to
+                // pass the alias component name instead to the client.
+                final ComponentName clientSideComponentName =
+                        res.aliasComponent != null ? res.aliasComponent : s.name;
                 try {
-                    c.conn.connected(s.name, b.intent.binder, false);
+                    c.conn.connected(clientSideComponentName, b.intent.binder, false);
                 } catch (Exception e) {
                     Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                             + " to connection " + c.conn.asBinder()
@@ -2910,8 +3003,12 @@
                                 continue;
                             }
                             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
+                            // If what the client try to start/connect was an alias, then we need to
+                            // pass the alias component name instead to the client.
+                            final ComponentName clientSideComponentName =
+                                    c.aliasComponent != null ? c.aliasComponent : r.name;
                             try {
-                                c.conn.connected(r.name, service, false);
+                                c.conn.connected(clientSideComponentName, service, false);
                             } catch (Exception e) {
                                 Slog.w(TAG, "Failure sending service " + r.shortInstanceName
                                       + " to connection " + c.conn.asBinder()
@@ -3063,9 +3160,22 @@
         final ServiceRecord record;
         final String permission;
 
-        ServiceLookupResult(ServiceRecord _record, String _permission) {
+        /**
+         * Set only when we looked up to this service via an alias. Otherwise, it's null.
+         */
+        @Nullable
+        final ComponentName aliasComponent;
+
+        ServiceLookupResult(ServiceRecord _record, ComponentName _aliasComponent) {
             record = _record;
+            permission = null;
+            aliasComponent = _aliasComponent;
+        }
+
+        ServiceLookupResult(String _permission) {
+            record = null;
             permission = _permission;
+            aliasComponent = null;
         }
     }
 
@@ -3097,10 +3207,19 @@
                 /* name= */ "service", callingPackage);
 
         ServiceMap smap = getServiceMapLocked(userId);
+
+        // See if the intent refers to an alias. If so, update the intent with the target component
+        // name. `resolution` will contain the alias component name, which we need to return
+        // to the client.
+        final ComponentAliasResolver.Resolution<ComponentName> resolution =
+                mAm.mComponentAliasResolver.resolveService(service, resolvedType,
+                        /* match flags */ 0, userId, callingUid);
+
         final ComponentName comp;
         if (instanceName == null) {
             comp = service.getComponent();
         } else {
+            // This is for isolated services
             final ComponentName realComp = service.getComponent();
             if (realComp == null) {
                 throw new IllegalArgumentException("Can't use custom instance name '" + instanceName
@@ -3109,6 +3228,7 @@
             comp = new ComponentName(realComp.getPackageName(),
                     realComp.getClassName() + ":" + instanceName);
         }
+
         if (comp != null) {
             r = smap.mServicesByInstanceName.get(comp);
             if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
@@ -3166,7 +3286,7 @@
                     String msg = "association not allowed between packages "
                             + callingPackage + " and " + name.getPackageName();
                     Slog.w(TAG, "Service lookup failed: " + msg);
-                    return new ServiceLookupResult(null, msg);
+                    return new ServiceLookupResult(msg);
                 }
 
                 // Store the defining packageName and uid, as they might be changed in
@@ -3284,11 +3404,11 @@
                 String msg = "association not allowed between packages "
                         + callingPackage + " and " + r.packageName;
                 Slog.w(TAG, "Service lookup failed: " + msg);
-                return new ServiceLookupResult(null, msg);
+                return new ServiceLookupResult(msg);
             }
             if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
                     resolvedType, r.appInfo)) {
-                return new ServiceLookupResult(null, "blocked by firewall");
+                return new ServiceLookupResult("blocked by firewall");
             }
             if (mAm.checkComponentPermission(r.permission,
                     callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
@@ -3297,14 +3417,14 @@
                             + " from pid=" + callingPid
                             + ", uid=" + callingUid
                             + " that is not exported from uid " + r.appInfo.uid);
-                    return new ServiceLookupResult(null, "not exported from uid "
+                    return new ServiceLookupResult("not exported from uid "
                             + r.appInfo.uid);
                 }
                 Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
                         + " from pid=" + callingPid
                         + ", uid=" + callingUid
                         + " requires " + r.permission);
-                return new ServiceLookupResult(null, r.permission);
+                return new ServiceLookupResult(r.permission);
             } else if (Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
                     && callingUid != Process.SYSTEM_UID) {
                 // Hotword detection must run in its own sandbox, and we don't even trust
@@ -3315,7 +3435,7 @@
                         + ", uid=" + callingUid
                         + " requiring permission " + r.permission
                         + " can only be bound to from the system.");
-                return new ServiceLookupResult(null, "can only be bound to "
+                return new ServiceLookupResult("can only be bound to "
                         + "by the system.");
             } else if (r.permission != null && callingPackage != null) {
                 final int opCode = AppOpsManager.permissionToOpCode(r.permission);
@@ -3328,7 +3448,7 @@
                     return null;
                 }
             }
-            return new ServiceLookupResult(r, null);
+            return new ServiceLookupResult(r, resolution.getAlias());
         }
         return null;
     }
@@ -3378,9 +3498,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;
@@ -3469,6 +3591,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;
@@ -3536,56 +3660,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) {
@@ -3598,6 +3755,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;
@@ -3653,8 +3965,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;
             }
         }
@@ -3684,6 +3998,9 @@
                         performScheduleRestartLocked(r, "Rescheduling", reason, now);
                     }
                 }
+                // mRestartingServices is sorted by nextRestartTime.
+                Collections.sort(mRestartingServices,
+                        (a, b) -> (int) (a.nextRestartTime - b.nextRestartTime));
             }
         } else {
             removeServiceRestartBackoffEnabledLocked(packageName);
@@ -4131,6 +4448,8 @@
                 // being brought down.  Mark it as dead.
                 cr.serviceDead = true;
                 cr.stopAssociation();
+                final ComponentName clientSideComponentName =
+                        cr.aliasComponent != null ? cr.aliasComponent : r.name;
                 try {
                     cr.conn.connected(r.name, null, true);
                 } catch (Exception e) {
@@ -4174,9 +4493,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);
@@ -4233,9 +4554,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),
@@ -4303,13 +4626,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;
+                }
             }
         }
 
@@ -4440,8 +4765,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);
@@ -4533,12 +4860,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);
     }
@@ -4585,13 +4914,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) {
@@ -4606,6 +4937,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;
@@ -4649,6 +4985,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
@@ -4657,6 +4994,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;
@@ -4937,7 +5286,7 @@
                 psr.updateBoundClientUids();
             }
 
-            // Sanity check: if the service listed for the app is not one
+            // Check: if the service listed for the app is not one
             // we actually are maintaining, just let it drop.
             final ServiceRecord curRec = smap.mServicesByInstanceName.get(sr.instanceName);
             if (curRec != sr) {
@@ -4976,8 +5325,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());
+                        }
                     }
                 }
             }
@@ -6278,10 +6629,17 @@
             final String msg = "Background started FGS: "
                     + ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
                     + r.mInfoAllowStartForeground;
-            Slog.wtfQuiet(TAG, msg);
             if (r.mAllowStartForeground != REASON_DENIED) {
+                if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
+                        mAm.mConstants.mFgsStartAllowedLogSampleRate)) {
+                    Slog.wtfQuiet(TAG, msg);
+                }
                 Slog.i(TAG, msg);
             } else {
+                if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
+                        mAm.mConstants.mFgsStartDeniedLogSampleRate)) {
+                    Slog.wtfQuiet(TAG, msg);
+                }
                 Slog.w(TAG, msg);
             }
             r.mLoggedInfoAllowStartForeground = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index ac0a198..db49b56 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;
@@ -52,7 +56,8 @@
     private static final String TAG = "ActivityManagerConstants";
 
     // Key names stored in the settings value.
-    private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
+    static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
+
     private static final String KEY_FGSERVICE_MIN_SHOWN_TIME
             = "fgservice_min_shown_time";
     private static final String KEY_FGSERVICE_MIN_REPORT_TIME
@@ -108,10 +113,20 @@
     static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration";
     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_START_ALLOWED_LOG_SAMPLE_RATE = "fgs_start_allowed_log_sample_rate";
+    static final String KEY_FGS_START_DENIED_LOG_SAMPLE_RATE = "fgs_start_denied_log_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";
+    static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
+    static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
+            "kill_bg_restricted_cached_idle_settle_time";
+    static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias";
+    static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
-    private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
     private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
     private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
     private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
@@ -152,6 +167,14 @@
     private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000;
     private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
     private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
+    private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
+    private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
+    private static final long DEFAULT_PROCESS_KILL_TIMEOUT_MS = 10 * 1000;
+
+    static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
+    static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
+    static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = true;
+
     /**
      * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
      */
@@ -159,6 +182,27 @@
             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;
+    private static final boolean DEFAULT_ENABLE_COMPONENT_ALIAS = false;
+    private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = "";
+
     // Flag stored in the DeviceConfig API.
     /**
      * Maximum number of cached processes.
@@ -243,6 +287,11 @@
     private static final String KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR =
             "push_messaging_over_quota_behavior";
 
+    /**
+     * Time in milliseconds; the allowed duration from a process is killed until it's really gone.
+     */
+    private static final String KEY_PROCESS_KILL_TIMEOUT = "process_kill_timeout";
+
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
 
@@ -496,11 +545,65 @@
     volatile float mFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE;
 
     /**
+     * Sample rate for the allowed FGS start WTF logs.
+     *
+     * If the value is 0.1, 10% of the logs would be sampled.
+     */
+    volatile float mFgsStartAllowedLogSampleRate = DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE;
+
+    /**
+     * Sample rate for the denied FGS start WTF logs.
+     *
+     * If the value is 0.1, 10% of the logs would be sampled.
+     */
+    volatile float mFgsStartDeniedLogSampleRate = DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE;
+
+    /**
+     * Whether or not to kill apps in background restricted mode and it's cached, its UID state is
+     * idle.
+     */
+    volatile boolean mKillBgRestrictedAndCachedIdle = DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE;
+
+    /**
+     * The amount of time we allow an app in background restricted mode to settle after it goes
+     * into the cached &amp; UID idle, before we decide to kill it.
+     */
+    volatile long mKillBgRestrictedAndCachedIdleSettleTimeMs =
+            DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS;
+
+    /**
+     * The allowed duration from a process is killed until it's really gone.
+     */
+    volatile long mProcessKillTimeoutMs = DEFAULT_PROCESS_KILL_TIMEOUT_MS;
+
+    /**
      * Whether to allow "opt-out" from the foreground service restrictions.
      * (https://developer.android.com/about/versions/12/foreground-services)
      */
     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;
+    /** Whether to enable "component alias" experimental feature. */
+    volatile boolean mEnableComponentAlias = DEFAULT_ENABLE_COMPONENT_ALIAS;
+
+    /**
+     * Defines component aliases. Format
+     * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
+     */
+    volatile String mComponentAliasOverrides = DEFAULT_COMPONENT_ALIAS_OVERRIDES;
+
     private final ActivityManagerService mService;
     private ContentResolver mResolver;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -711,9 +814,34 @@
                             case KEY_FGS_ATOM_SAMPLE_RATE:
                                 updateFgsAtomSamplePercent();
                                 break;
+                            case KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE:
+                                updateFgsStartAllowedLogSamplePercent();
+                                break;
+                            case KEY_FGS_START_DENIED_LOG_SAMPLE_RATE:
+                                updateFgsStartDeniedLogSamplePercent();
+                                break;
+                            case KEY_KILL_BG_RESTRICTED_CACHED_IDLE:
+                                updateKillBgRestrictedCachedIdle();
+                                break;
+                            case KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME:
+                                updateKillBgRestrictedCachedIdleSettleTime();
+                                break;
                             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;
+                            case KEY_ENABLE_COMPONENT_ALIAS:
+                            case KEY_COMPONENT_ALIAS_OVERRIDES:
+                                updateComponentAliases();
+                                break;
+                            case KEY_PROCESS_KILL_TIMEOUT:
+                                updateProcessKillTimeout();
+                                break;
                             default:
                                 break;
                         }
@@ -1057,6 +1185,42 @@
                 DEFAULT_FGS_ATOM_SAMPLE_RATE);
     }
 
+    private void updateFgsStartAllowedLogSamplePercent() {
+        mFgsStartAllowedLogSampleRate = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE,
+                DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE);
+    }
+
+    private void updateFgsStartDeniedLogSamplePercent() {
+        mFgsStartDeniedLogSampleRate = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_FGS_START_DENIED_LOG_SAMPLE_RATE,
+                DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE);
+    }
+
+    private void updateKillBgRestrictedCachedIdle() {
+        mKillBgRestrictedAndCachedIdle = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_KILL_BG_RESTRICTED_CACHED_IDLE,
+                DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE);
+    }
+
+    private void updateKillBgRestrictedCachedIdleSettleTime() {
+        final long currentSettleTime = mKillBgRestrictedAndCachedIdleSettleTimeMs;
+        mKillBgRestrictedAndCachedIdleSettleTimeMs = DeviceConfig.getLong(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
+                DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
+        if (mKillBgRestrictedAndCachedIdleSettleTimeMs != currentSettleTime) {
+            mService.mHandler.removeMessages(
+                    ActivityManagerService.IDLE_UIDS_MSG);
+            mService.mHandler.sendEmptyMessageDelayed(
+                    ActivityManagerService.IDLE_UIDS_MSG,
+                    mKillBgRestrictedAndCachedIdleSettleTimeMs);
+        }
+    }
+
     private void updateFgsAllowOptOut() {
         mFgsAllowOptOut = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1064,6 +1228,70 @@
                 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 updateComponentAliases() {
+        mEnableComponentAlias = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_ENABLE_COMPONENT_ALIAS,
+                DEFAULT_ENABLE_COMPONENT_ALIAS);
+        mComponentAliasOverrides = DeviceConfig.getString(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPONENT_ALIAS_OVERRIDES,
+                DEFAULT_COMPONENT_ALIAS_OVERRIDES);
+        mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
+    }
+
+    private void updateProcessKillTimeout() {
+        mProcessKillTimeoutMs = DeviceConfig.getLong(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_PROCESS_KILL_TIMEOUT,
+                DEFAULT_PROCESS_KILL_TIMEOUT_MS);
+    }
+
     private void updateImperceptibleKillExemptions() {
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
@@ -1285,10 +1513,18 @@
         pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk);
         pw.print("  "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE);
         pw.print("="); pw.println(mFgsAtomSampleRate);
+        pw.print("  "); pw.print(KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE);
+        pw.print("="); pw.println(mFgsStartAllowedLogSampleRate);
+        pw.print("  "); pw.print(KEY_FGS_START_DENIED_LOG_SAMPLE_RATE);
+        pw.print("="); pw.println(mFgsStartDeniedLogSampleRate);
         pw.print("  "); pw.print(KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR);
         pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
         pw.print("  "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
         pw.print("="); pw.println(mFgsAllowOptOut);
+        pw.print("  "); pw.print(KEY_ENABLE_COMPONENT_ALIAS);
+        pw.print("="); pw.println(mEnableComponentAlias);
+        pw.print("  "); pw.print(KEY_COMPONENT_ALIAS_OVERRIDES);
+        pw.print("="); pw.println(mComponentAliasOverrides);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 35ed477..a369123 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -121,6 +121,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.MemoryStatUtil.hasMemcg;
+import static com.android.server.am.ProcessList.ProcStartHandler;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -194,6 +195,9 @@
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetManagerInternal;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.AttributionSource;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
@@ -258,6 +262,7 @@
 import android.os.IPermissionController;
 import android.os.IProcessInfoService;
 import android.os.IProgressListener;
+import android.os.InputConstants;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -543,6 +548,16 @@
     static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
 
     /**
+     * It is now required for apps to explicitly set either
+     * {@link android.content.Context#RECEIVER_EXPORTED} or
+     * {@link android.content.Context#RECEIVER_NOT_EXPORTED} when registering a receiver for an
+     * unprotected broadcast in code.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
+
+    /**
      * The maximum number of bytes that {@link #setProcessStateSummary} accepts.
      *
      * @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])}
@@ -778,6 +793,9 @@
     @GuardedBy("this")
     private ArrayMap<String, PackageAssociationInfo> mAllowedAssociations;
 
+    @GuardedBy("this")
+    final ComponentAliasResolver mComponentAliasResolver;
+
     /**
      * Tracks association information for a particular package along with debuggability.
      * <p> Associations for a package A are allowed to package B if B is part of the
@@ -1485,7 +1503,7 @@
     final MainHandler mHandler;
     final Handler mUiHandler;
     final ServiceThread mProcStartHandlerThread;
-    final Handler mProcStartHandler;
+    final ProcStartHandler mProcStartHandler;
 
     ActivityManagerConstants mConstants;
 
@@ -1674,7 +1692,7 @@
             case PROC_START_TIMEOUT_MSG: {
                 ProcessRecord app = (ProcessRecord) msg.obj;
                 synchronized (ActivityManagerService.this) {
-                    processStartTimedOutLocked(app);
+                    handleProcessStartOrKillTimeoutLocked(app, /* isKillTimeout */ false);
                 }
             } break;
             case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
@@ -2219,6 +2237,7 @@
         mUseFifoUiScheduling = false;
         mEnableOffloadQueue = false;
         mFgBroadcastQueue = mBgBroadcastQueue = mOffloadBroadcastQueue = null;
+        mComponentAliasResolver = new ComponentAliasResolver(this);
     }
 
     // Note: This method is invoked on the main thread but may need to attach various
@@ -2243,7 +2262,7 @@
         mProcStartHandlerThread = new ServiceThread(TAG + ":procStart",
                 THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
         mProcStartHandlerThread.start();
-        mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
+        mProcStartHandler = new ProcStartHandler(this, mProcStartHandlerThread.getLooper());
 
         mConstants = new ActivityManagerConstants(mContext, this, mHandler);
         final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
@@ -2345,6 +2364,7 @@
         mInternal = new LocalService();
         mPendingStartActivityUids = new PendingStartActivityUids(mContext);
         mTraceErrorLogger = new TraceErrorLogger();
+        mComponentAliasResolver = new ComponentAliasResolver(this);
     }
 
     public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -4235,47 +4255,81 @@
     }
 
     @GuardedBy("this")
-    private final void processStartTimedOutLocked(ProcessRecord app) {
+    void handleProcessStartOrKillTimeoutLocked(ProcessRecord app, boolean isKillTimeout) {
         final int pid = app.getPid();
-        boolean gone = removePidIfNoThreadLocked(app);
+        boolean gone = isKillTimeout || removePidIfNoThreadLocked(app);
 
         if (gone) {
-            Slog.w(TAG, "Process " + app + " failed to attach");
-            EventLogTags.writeAmProcessStartTimeout(app.userId, pid, app.uid, app.processName);
+            if (isKillTimeout) {
+                // It's still alive... maybe blocked at uninterruptible sleep ?
+                final ProcessRecord successor = app.mSuccessor;
+                if (successor == null) {
+                    // There might be a race, nothing to do here.
+                    return;
+                }
+                Slog.wtf(TAG, app.toString() + " " + app.getDyingPid()
+                        + " refused to die while trying to launch " + successor
+                        + ", cancelling the process start");
+
+                // It doesn't make sense to proceed with launching the new instance while the old
+                // instance is still alive, abort the launch.
+                app.mSuccessorStartRunnable = null;
+                app.mSuccessor = null;
+                successor.mPredecessor = null;
+
+                // We're going to cleanup the successor process record, which wasn't started at all.
+                app = successor;
+            } else {
+                Slog.w(TAG, "Process " + app + " failed to attach");
+                EventLogTags.writeAmProcessStartTimeout(app.userId, pid, app.uid, app.processName);
+            }
             synchronized (mProcLock) {
                 mProcessList.removeProcessNameLocked(app.processName, app.uid);
                 mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
-                mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
                 // Take care of any launching providers waiting for this process.
                 mCpHelper.cleanupAppInLaunchingProvidersLocked(app, true);
                 // Take care of any services that are waiting for the process.
                 mServices.processStartTimedOutLocked(app);
-                app.killLocked("start timeout", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
-                        true);
+                if (!isKillTimeout) {
+                    mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
+                    app.killLocked("start timeout",
+                            ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
+                    removeLruProcessLocked(app);
+                }
                 if (app.isolated) {
                     mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+                    mProcessList.mAppExitInfoTracker.mIsolatedUidRecords.removeIsolatedUid(
+                            app.uid, app.info.uid);
+                    getPackageManagerInternal().removeIsolatedUid(app.uid);
                 }
-                removeLruProcessLocked(app);
             }
             final BackupRecord backupTarget = mBackupTargets.get(app.userId);
-            if (backupTarget != null && backupTarget.app.getPid() == pid) {
+            if (!isKillTimeout && backupTarget != null && backupTarget.app.getPid() == pid) {
                 Slog.w(TAG, "Unattached app died before backup, skipping");
+                final int userId = app.userId;
+                final String packageName = app.info.packageName;
                 mHandler.post(new Runnable() {
                 @Override
                     public void run(){
                         try {
                             IBackupManager bm = IBackupManager.Stub.asInterface(
                                     ServiceManager.getService(Context.BACKUP_SERVICE));
-                            bm.agentDisconnectedForUser(app.userId, app.info.packageName);
+                            bm.agentDisconnectedForUser(userId, packageName);
                         } catch (RemoteException e) {
                             // Can't happen; the backup manager is local
                         }
                     }
                 });
             }
-            if (isPendingBroadcastProcessLocked(pid)) {
-                Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
-                skipPendingBroadcastLocked(pid);
+            if (!isKillTimeout) {
+                if (isPendingBroadcastProcessLocked(pid)) {
+                    Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+                    skipPendingBroadcastLocked(pid);
+                }
+            } else {
+                if (isPendingBroadcastProcessLocked(app)) {
+                    skipCurrentReceiverLocked(app);
+                }
             }
         } else {
             Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
@@ -4783,6 +4837,10 @@
         showConsoleNotificationIfActive();
 
         t.traceEnd();
+
+        // Load the component aliases.
+        mComponentAliasResolver.update(
+                mConstants.mEnableComponentAlias, mConstants.mComponentAliasOverrides);
     }
 
     private void showConsoleNotificationIfActive() {
@@ -5707,7 +5765,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 +5773,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;
     }
@@ -8790,6 +8848,12 @@
                 pw.println("-------------------------------------------------------------------------------");
             }
             dumpUsers(pw);
+
+            pw.println();
+            if (dumpAll) {
+                pw.println("-------------------------------------------------------------------------------");
+            }
+            mComponentAliasResolver.dump(pw);
         }
     }
 
@@ -9106,6 +9170,8 @@
                     opti++;
                 }
                 mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
+            } else if ("component-alias".equals(cmd)) {
+                mComponentAliasResolver.dump(pw);
             } else {
                 // Dumping a single activity?
                 if (!mAtmInternal.dumpActivity(fd, pw, cmd, args, opti, dumpAll,
@@ -9482,6 +9548,15 @@
                 TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
                 pw.println();
             });
+
+            if (!mProcessList.mAppsInBackgroundRestricted.isEmpty()) {
+                pw.println("  Processes that are in background restricted:");
+                for (int i = 0, size = mProcessList.mAppsInBackgroundRestricted.size();
+                        i < size; i++) {
+                    pw.println(String.format("%s #%2d: %s", "    ", i,
+                            mProcessList.mAppsInBackgroundRestricted.valueAt(i).toString()));
+                }
+            }
         }
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
@@ -12354,6 +12429,12 @@
                 || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(pid);
     }
 
+    boolean isPendingBroadcastProcessLocked(ProcessRecord app) {
+        return mFgBroadcastQueue.isPendingBroadcastProcessLocked(app)
+                || mBgBroadcastQueue.isPendingBroadcastProcessLocked(app)
+                || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(app);
+    }
+
     void skipPendingBroadcastLocked(int pid) {
             Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
             for (BroadcastQueue queue : mBroadcastQueues) {
@@ -12389,6 +12470,12 @@
         ProcessRecord callerApp = null;
         final boolean visibleToInstantApps
                 = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
+        // Dynamic receivers are exported by default for versions prior to T
+        final boolean exported =
+                ((flags & Context.RECEIVER_EXPORTED) != 0
+                        || (!Compatibility.isChangeEnabled(
+                                DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED)));
+
         int callingUid;
         int callingPid;
         boolean instantApp;
@@ -12425,8 +12512,10 @@
                 noAction.add(null);
                 actions = noAction.iterator();
             }
+            boolean onlyProtectedBroadcasts = actions.hasNext();
 
-            // Collect stickies of users
+            // Collect stickies of users and check if broadcast is only registered for protected
+            // broadcasts
             int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
             while (actions.hasNext()) {
                 String action = actions.next();
@@ -12442,6 +12531,32 @@
                         }
                     }
                 }
+                if (onlyProtectedBroadcasts) {
+                    try {
+                        onlyProtectedBroadcasts &=
+                                AppGlobals.getPackageManager().isProtectedBroadcast(action);
+                    } catch (RemoteException e) {
+                        onlyProtectedBroadcasts = false;
+                        Slog.w(TAG, "Remote exception", e);
+                    }
+                }
+            }
+
+            // If the change is enabled, but neither exported or not exported is set, we need to log
+            // an error so the consumer can know to explicitly set the value for their flag
+            if (!onlyProtectedBroadcasts && (Compatibility.isChangeEnabled(
+                    DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED)
+                    && (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED))
+                    == 0)) {
+                Slog.e(TAG,
+                        callerPackage + ": Targeting T+ (version " + Build.VERSION_CODES.TIRAMISU
+                                + " and above) requires that one of RECEIVER_EXPORTED or "
+                                + "RECEIVER_NOT_EXPORTED be specified when registering a receiver");
+            } else if (((flags & Context.RECEIVER_EXPORTED) != 0) && (
+                    (flags & Context.RECEIVER_NOT_EXPORTED) != 0)) {
+                throw new IllegalArgumentException(
+                        "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED"
+                                + "flag");
             }
         }
 
@@ -12530,7 +12645,8 @@
                         + " callerPackage is " + callerPackage);
             }
             BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
-                    receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);
+                    receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
+                    exported);
             if (rl.containsFilter(filter)) {
                 Slog.w(TAG, "Receiver with filter " + filter
                         + " already registered for pid " + rl.pid
@@ -12628,76 +12744,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 +13443,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);
         }
@@ -14433,6 +14544,10 @@
         final int capability = uidRec != null ? uidRec.getSetCapability() : 0;
         final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid);
 
+        if (uidRec != null && uidRec.isIdle() && (change & UidRecord.CHANGE_IDLE) != 0) {
+            mProcessList.killAppIfBgRestrictedAndCachedIdleLocked(uidRec);
+        }
+
         if (uidRec != null && !uidRec.isIdle() && (change & UidRecord.CHANGE_GONE) != 0) {
             // If this uid is going away, and we haven't yet reported it is gone,
             // then do so now.
@@ -15332,6 +15447,12 @@
     @VisibleForTesting
     public final class LocalService extends ActivityManagerInternal
             implements ActivityManagerLocal {
+
+        @Override
+        public Pair<String, String> getAppProfileStatsForDebugging(long time, int lines) {
+            return mAppProfiler.getAppProfileStatsForDebugging(time, lines);
+        }
+
         @Override
         public String checkContentProviderAccess(String authority, int userId) {
             return mCpHelper.checkContentProviderAccess(authority, userId);
@@ -15986,8 +16107,22 @@
 
         @Override
         public void inputDispatchingResumed(int pid) {
-            // TODO (b/171218828)
-            return;
+            final ProcessRecord proc;
+            synchronized (mPidsSelfLocked) {
+                proc = mPidsSelfLocked.get(pid);
+            }
+            if (proc != null) {
+                mAppErrors.handleDismissAnrDialogs(proc);
+            }
+        }
+
+        @Override
+        public void rescheduleAnrDialog(Object data) {
+            Message msg = Message.obtain();
+            msg.what = SHOW_NOT_RESPONDING_UI_MSG;
+            msg.obj = (AppNotRespondingDialog.Data) data;
+
+            mUiHandler.sendMessageDelayed(msg, InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
         }
 
         @Override
@@ -16630,13 +16765,21 @@
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                 "scheduleApplicationInfoChanged()");
 
-        synchronized (mProcLock) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                updateApplicationInfoLOSP(packageNames, userId);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            final boolean updateFrameworkRes = packageNames.contains("android");
+            synchronized (mProcLock) {
+                updateApplicationInfoLOSP(packageNames, updateFrameworkRes, userId);
             }
+
+            AppWidgetManagerInternal widgets = LocalServices.getService(
+                    AppWidgetManagerInternal.class);
+            if (widgets != null) {
+                widgets.applyResourceOverlaysToWidgets(new HashSet<>(packageNames), userId,
+                        updateFrameworkRes);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -16653,18 +16796,12 @@
     }
 
     @GuardedBy(anyOf = {"this", "mProcLock"})
-    private void updateApplicationInfoLOSP(@NonNull List<String> packagesToUpdate, int userId) {
-        final boolean updateFrameworkRes = packagesToUpdate.contains("android");
+    private void updateApplicationInfoLOSP(@NonNull List<String> packagesToUpdate,
+            boolean updateFrameworkRes, int userId) {
         if (updateFrameworkRes) {
             ParsingPackageUtils.readConfigUseRoundIcon(null);
         }
 
-        AppWidgetManagerInternal widgets = LocalServices.getService(AppWidgetManagerInternal.class);
-        if (widgets != null) {
-            widgets.applyResourceOverlaysToWidgets(new HashSet<>(packagesToUpdate), userId,
-                    updateFrameworkRes);
-        }
-
         mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);
 
         if (updateFrameworkRes) {
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index bcb42bb..0dfdfe9 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -1058,6 +1058,7 @@
         }
         synchronized (mProcLock) {
             final ProcessErrorStateRecord errState = proc.mErrorState;
+            errState.setAnrData(data);
             if (!proc.isPersistent()) {
                 packageList = proc.getPackageListWithVersionCode();
             }
@@ -1109,6 +1110,24 @@
         }
     }
 
+    void handleDismissAnrDialogs(ProcessRecord proc) {
+        synchronized (mProcLock) {
+            final ProcessErrorStateRecord errState = proc.mErrorState;
+
+            // Cancel any rescheduled ANR dialogs
+            mService.mUiHandler.removeMessages(
+                    ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG, errState.getAnrData());
+
+            // Dismiss any ANR dialogs currently visible
+            if (errState.getDialogController().hasAnrDialogs()) {
+                errState.setNotResponding(false);
+                errState.setNotRespondingReport(null);
+                errState.getDialogController().clearAnrDialogs();
+            }
+            proc.mErrorState.setAnrData(null);
+        }
+    }
+
     /**
      * Information about a process that is currently marked as bad.
      */
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 979a9ee..fc29982 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -1507,6 +1507,20 @@
             }
         }
 
+        void removeIsolatedUid(int isolatedUid, int uid) {
+            synchronized (mLock) {
+                final int index = mUidToIsolatedUidMap.indexOfKey(uid);
+                if (index >= 0) {
+                    final ArraySet<Integer> set = mUidToIsolatedUidMap.valueAt(index);
+                    set.remove(isolatedUid);
+                    if (set.isEmpty()) {
+                        mUidToIsolatedUidMap.removeAt(index);
+                    }
+                }
+                mIsolatedUidToUidMap.remove(isolatedUid);
+            }
+        }
+
         @GuardedBy("mLock")
         Integer getUidByIsolatedUid(int isolatedUid) {
             if (UserHandle.isIsolated(isolatedUid)) {
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index b233a2c..878ef31 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -48,12 +48,14 @@
 
     private final ActivityManagerService mService;
     private final ProcessRecord mProc;
+    private final Data mData;
 
     public AppNotRespondingDialog(ActivityManagerService service, Context context, Data data) {
         super(context);
 
         mService = service;
         mProc = data.proc;
+        mData = data;
         Resources res = context.getResources();
 
         setCancelable(false);
@@ -165,6 +167,8 @@
                             errState.getDialogController().clearAnrDialogs();
                         }
                         mService.mServices.scheduleServiceTimeoutLocked(app);
+                        // If the app remains unresponsive, show the dialog again after a delay.
+                        mService.mInternal.rescheduleAnrDialog(mData);
                     }
                     break;
             }
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 36c0de9..d44d729 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();
@@ -1033,6 +1047,7 @@
                     mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now);
                     state.setProcStateChanged(false);
                 }
+                trimMemoryUiHiddenIfNecessaryLSP(app);
                 if (curProcState >= ActivityManager.PROCESS_STATE_HOME && !app.isKilledByAm()) {
                     if (trimMemoryLevel < curLevel[0] && (thread = app.getThread()) != null) {
                         try {
@@ -1075,24 +1090,6 @@
                     }
                     profile.setTrimMemoryLevel(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
                 } else {
-                    if ((curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
-                                || state.isSystemNoUi()) && profile.hasPendingUiClean()) {
-                        // If this application is now in the background and it
-                        // had done UI, then give it the special trim level to
-                        // have it free UI resources.
-                        final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
-                        if (trimMemoryLevel < level && (thread = app.getThread()) != null) {
-                            try {
-                                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
-                                    Slog.v(TAG_OOM_ADJ, "Trimming memory of bg-ui "
-                                            + app.processName + " to " + level);
-                                }
-                                thread.scheduleTrimMemory(level);
-                            } catch (RemoteException e) {
-                            }
-                        }
-                        profile.setPendingUiClean(false);
-                    }
                     if (trimMemoryLevel < fgTrimLevel && (thread = app.getThread()) != null) {
                         try {
                             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
@@ -1119,28 +1116,36 @@
                     mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now);
                     state.setProcStateChanged(false);
                 }
-                if ((state.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
-                            || state.isSystemNoUi()) && profile.hasPendingUiClean()) {
-                    if (profile.getTrimMemoryLevel() < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
-                            && (thread = app.getThread()) != null) {
-                        try {
-                            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
-                                Slog.v(TAG_OOM_ADJ,
-                                        "Trimming memory of ui hidden " + app.processName
-                                        + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
-                            }
-                            thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                    profile.setPendingUiClean(false);
-                }
+                trimMemoryUiHiddenIfNecessaryLSP(app);
                 profile.setTrimMemoryLevel(0);
             });
         }
         return allChanged;
     }
 
+    @GuardedBy({"mService", "mProcLock"})
+    private void trimMemoryUiHiddenIfNecessaryLSP(ProcessRecord app) {
+        if ((app.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+                || app.mState.isSystemNoUi()) && app.mProfile.hasPendingUiClean()) {
+            // If this application is now in the background and it
+            // had done UI, then give it the special trim level to
+            // have it free UI resources.
+            final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+            IApplicationThread thread;
+            if (app.mProfile.getTrimMemoryLevel() < level && (thread = app.getThread()) != null) {
+                try {
+                    if (DEBUG_SWITCH || DEBUG_OOM_ADJ) {
+                        Slog.v(TAG_OOM_ADJ, "Trimming memory of bg-ui "
+                                + app.processName + " to " + level);
+                    }
+                    thread.scheduleTrimMemory(level);
+                } catch (RemoteException e) {
+                }
+            }
+            app.mProfile.setPendingUiClean(false);
+        }
+    }
+
     @GuardedBy("mProcLock")
     long getLowRamTimeSinceIdleLPr(long now) {
         return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now - mLowRamStartTime) : 0);
@@ -1636,6 +1641,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()) {
@@ -2318,6 +2330,27 @@
         }
     }
 
+    Pair<String, String> getAppProfileStatsForDebugging(long time, int linesOfStats) {
+        String cpuLoad = null;
+        String stats = null;
+        synchronized (mProcessCpuTracker) {
+            updateCpuStatsNow();
+            cpuLoad = mProcessCpuTracker.printCurrentLoad();
+            stats = mProcessCpuTracker.printCurrentState(time);
+        }
+        // Only return linesOfStats lines of Cpu stats.
+        int toIndex = 0;
+        for (int i = 0; i <= linesOfStats; i++) {
+            int nextIndex = stats.indexOf('\n', toIndex);
+            if (nextIndex == -1) {
+                toIndex = stats.length();
+                break;
+            }
+            toIndex = nextIndex + 1;
+        }
+        return new Pair(cpuLoad, stats.substring(0, toIndex));
+    }
+
     @GuardedBy("mProfilerLock")
     void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
         if (mProcessesToGc.size() > 0) {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 449f02e..3c6b682 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -492,7 +492,7 @@
                     for (int uid : uidsToRemove) {
                         FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, -1, uid,
                                 FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__REMOVED);
-                        mStats.removeIsolatedUidLocked(uid, SystemClock.elapsedRealtime(),
+                        mStats.maybeRemoveIsolatedUidLocked(uid, SystemClock.elapsedRealtime(),
                                 SystemClock.uptimeMillis());
                     }
                     mStats.clearPendingRemovedUidsLocked();
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 50e06c3..8e38f0a 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -34,10 +34,12 @@
     final int owningUserId;
     final boolean instantApp;
     final boolean visibleToInstantApp;
+    final boolean exported;
 
     BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
             String _packageName, String _featureId, String _receiverId, String _requiredPermission,
-            int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp) {
+            int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp,
+            boolean _exported) {
         super(_filter);
         receiverList = _receiverList;
         packageName = _packageName;
@@ -48,6 +50,7 @@
         owningUserId = _userId;
         instantApp = _instantApp;
         visibleToInstantApp = _visibleToInstantApp;
+        exported = _exported;
     }
 
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 503b3a9..ed70d2b 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -230,6 +230,10 @@
         return mPendingBroadcast != null && mPendingBroadcast.curApp.getPid() == pid;
     }
 
+    boolean isPendingBroadcastProcessLocked(ProcessRecord app) {
+        return mPendingBroadcast != null && mPendingBroadcast.curApp == app;
+    }
+
     public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
         mParallelBroadcasts.add(r);
         enqueueBroadcastHelper(r);
@@ -775,6 +779,22 @@
             skip = true;
         }
 
+        // Ensure that broadcasts are only sent to other apps if they are explicitly marked as
+        // exported, or are System level broadcasts
+        if (!skip && !filter.exported && Process.SYSTEM_UID != r.callingUid
+                && filter.receiverList.uid != r.callingUid) {
+
+            Slog.w(TAG, "Exported Denial: sending "
+                    + r.intent.toString()
+                    + ", action: " + r.intent.getAction()
+                    + " from " + r.callerPackage
+                    + " (uid=" + r.callingUid + ")"
+                    + " due to receiver " + filter.receiverList.app
+                    + " (uid " + filter.receiverList.uid + ")"
+                    + " not specifying RECEIVER_EXPORTED");
+            // skip = true;
+        }
+
         if (skip) {
             r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
             return;
diff --git a/services/core/java/com/android/server/am/CacheOomRanker.java b/services/core/java/com/android/server/am/CacheOomRanker.java
index 1ead7e3..7413808 100644
--- a/services/core/java/com/android/server/am/CacheOomRanker.java
+++ b/services/core/java/com/android/server/am/CacheOomRanker.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import android.os.Process;
+import android.os.SystemClock;
 import android.provider.DeviceConfig;
 import android.util.Slog;
 
@@ -46,6 +48,14 @@
     @VisibleForTesting
     static final int DEFAULT_PRESERVE_TOP_N_APPS = 3;
     @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_USE_FREQUENT_RSS = "oom_re_ranking_rss_use_frequent_rss";
+    @VisibleForTesting
+    static final boolean DEFAULT_USE_FREQUENT_RSS = true;
+    @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_RSS_UPDATE_RATE_MS = "oom_re_ranking_rss_update_rate_ms";
+    @VisibleForTesting
+    static final long DEFAULT_RSS_UPDATE_RATE_MS = 10_000; // 10 seconds
+    @VisibleForTesting
     static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight";
     @VisibleForTesting
     static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f;
@@ -62,6 +72,8 @@
             new ScoreComparator();
     private static final Comparator<RankedProcessRecord> CACHE_USE_COMPARATOR =
             new CacheUseComparator();
+    private static final Comparator<RankedProcessRecord> RSS_COMPARATOR =
+            new RssComparator();
     private static final Comparator<RankedProcessRecord> LAST_RSS_COMPARATOR =
             new LastRssComparator();
     private static final Comparator<RankedProcessRecord> LAST_ACTIVITY_TIME_COMPARATOR =
@@ -70,6 +82,7 @@
     private final Object mPhenotypeFlagLock = new Object();
 
     private final ActivityManagerService mService;
+    private final ProcessDependencies mProcessDependencies;
     private final ActivityManagerGlobalLock mProcLock;
     private final Object mProfilerLock;
 
@@ -78,6 +91,12 @@
     @GuardedBy("mPhenotypeFlagLock")
     @VisibleForTesting
     int mPreserveTopNApps = DEFAULT_PRESERVE_TOP_N_APPS;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting
+    boolean mUseFrequentRss = DEFAULT_USE_FREQUENT_RSS;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting
+    long mRssUpdateRateMs = DEFAULT_RSS_UPDATE_RATE_MS;
     // Weight to apply to the LRU ordering.
     @GuardedBy("mPhenotypeFlagLock")
     @VisibleForTesting
@@ -110,6 +129,10 @@
                                 updateNumberToReRank();
                             } else if (KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS.equals(name)) {
                                 updatePreserveTopNApps();
+                            } else if (KEY_OOM_RE_RANKING_USE_FREQUENT_RSS.equals(name)) {
+                                updateUseFrequentRss();
+                            } else if (KEY_OOM_RE_RANKING_RSS_UPDATE_RATE_MS.equals(name)) {
+                                updateRssUpdateRateMs();
                             } else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) {
                                 updateLruWeight();
                             } else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) {
@@ -123,9 +146,15 @@
             };
 
     CacheOomRanker(final ActivityManagerService service) {
+        this(service, new ProcessDependenciesImpl());
+    }
+
+    @VisibleForTesting
+    CacheOomRanker(final ActivityManagerService service, ProcessDependencies processDependencies) {
         mService = service;
         mProcLock = service.mProcLock;
         mProfilerLock = service.mAppProfiler.mProfilerLock;
+        mProcessDependencies = processDependencies;
     }
 
     /** Load settings from device config and register a listener for changes. */
@@ -190,6 +219,18 @@
     }
 
     @GuardedBy("mPhenotypeFlagLock")
+    private void updateRssUpdateRateMs() {
+        mRssUpdateRateMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_RSS_UPDATE_RATE_MS, DEFAULT_RSS_UPDATE_RATE_MS);
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateUseFrequentRss() {
+        mUseFrequentRss = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_USE_FREQUENT_RSS, DEFAULT_USE_FREQUENT_RSS);
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
     private void updateLruWeight() {
         mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 KEY_OOM_RE_RANKING_LRU_WEIGHT, DEFAULT_OOM_RE_RANKING_LRU_WEIGHT);
@@ -243,6 +284,9 @@
         float lruWeight;
         float usesWeight;
         float rssWeight;
+        int preserveTopNApps;
+        boolean useFrequentRss;
+        long rssUpdateRateMs;
         int[] lruPositions;
         RankedProcessRecord[] scoredProcessRecords;
 
@@ -250,6 +294,9 @@
             lruWeight = mLruWeight;
             usesWeight = mUsesWeight;
             rssWeight = mRssWeight;
+            preserveTopNApps = mPreserveTopNApps;
+            useFrequentRss = mUseFrequentRss;
+            rssUpdateRateMs = mRssUpdateRateMs;
             lruPositions = mLruPositions;
             scoredProcessRecords = mScoredProcessRecords;
         }
@@ -276,24 +323,50 @@
             ++numProcessesEvaluated;
         }
 
-        // Count how many apps we're not re-ranking (up to mPreserveTopNApps).
+        // Count how many apps we're not re-ranking (up to preserveTopNApps).
         int numProcessesNotReRanked = 0;
         while (numProcessesEvaluated < lruProcessServiceStart
-                && numProcessesNotReRanked < mPreserveTopNApps) {
+                && numProcessesNotReRanked < preserveTopNApps) {
             ProcessRecord process = lruList.get(numProcessesEvaluated);
             if (appCanBeReRanked(process)) {
                 numProcessesNotReRanked++;
             }
             numProcessesEvaluated++;
         }
-        // Exclude the top `mPreserveTopNApps` apps from re-ranking.
-        if (numProcessesNotReRanked < mPreserveTopNApps) {
-            numProcessesReRanked -= mPreserveTopNApps - numProcessesNotReRanked;
+        // Exclude the top `preserveTopNApps` apps from re-ranking.
+        if (numProcessesNotReRanked < preserveTopNApps) {
+            numProcessesReRanked -= preserveTopNApps - numProcessesNotReRanked;
             if (numProcessesReRanked < 0) {
                 numProcessesReRanked = 0;
             }
         }
 
+        if (useFrequentRss) {
+            // Update RSS values for re-ranked apps.
+            long nowMs = SystemClock.elapsedRealtime();
+            for (int i = 0; i < numProcessesReRanked; ++i) {
+                RankedProcessRecord scoredProcessRecord = scoredProcessRecords[i];
+                long sinceUpdateMs =
+                        nowMs - scoredProcessRecord.proc.mState.getCacheOomRankerRssTimeMs();
+                if (scoredProcessRecord.proc.mState.getCacheOomRankerRss() != 0
+                        && sinceUpdateMs < rssUpdateRateMs) {
+                    continue;
+                }
+
+                long[] rss = mProcessDependencies.getRss(scoredProcessRecord.proc.getPid());
+                if (rss == null || rss.length == 0) {
+                    Slog.e(
+                            OomAdjuster.TAG,
+                            "Process.getRss returned bad value, not re-ranking: "
+                                    + Arrays.toString(rss));
+                    return;
+                }
+                // First element is total RSS:
+                // frameworks/base/core/jni/android_util_Process.cpp:1192
+                scoredProcessRecord.proc.mState.setCacheOomRankerRss(rss[0], nowMs);
+            }
+        }
+
         // Add scores for each of the weighted features we want to rank based on.
         if (lruWeight > 0.0f) {
             // This doesn't use the LRU list ordering as after the first re-ranking
@@ -303,8 +376,12 @@
             addToScore(scoredProcessRecords, lruWeight);
         }
         if (rssWeight > 0.0f) {
-            synchronized (mService.mAppProfiler.mProfilerLock) {
-                Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, LAST_RSS_COMPARATOR);
+            if (useFrequentRss) {
+                Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, RSS_COMPARATOR);
+            } else {
+                synchronized (mService.mAppProfiler.mProfilerLock) {
+                    Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, LAST_RSS_COMPARATOR);
+                }
             }
             addToScore(scoredProcessRecords, rssWeight);
         }
@@ -383,6 +460,16 @@
         }
     }
 
+    private static class RssComparator implements Comparator<RankedProcessRecord> {
+        @Override
+        public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
+            // High RSS first to match least recently used.
+            return Long.compare(
+                    o2.proc.mState.getCacheOomRankerRss(),
+                    o1.proc.mState.getCacheOomRankerRss());
+        }
+    }
+
     private static class LastRssComparator implements Comparator<RankedProcessRecord> {
         @Override
         public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
@@ -395,4 +482,18 @@
         public ProcessRecord proc;
         public float score;
     }
+
+    /**
+     * Interface for mocking {@link Process} static methods.
+     */
+    interface ProcessDependencies {
+        long[] getRss(int pid);
+    }
+
+    private static class ProcessDependenciesImpl implements ProcessDependencies {
+        @Override
+        public long[] getRss(int pid) {
+            return Process.getRss(pid);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7c336d7..f32aa22 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -101,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;
@@ -276,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();
@@ -678,6 +678,8 @@
                     KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
             mUseFreezer = isFreezerSupported();
             updateFreezerDebounceTimeout();
+        } else {
+            mUseFreezer = false;
         }
 
         final boolean useFreezer = mUseFreezer;
diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java
new file mode 100644
index 0000000..3577f72
--- /dev/null
+++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java
@@ -0,0 +1,321 @@
+/*
+ * 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 android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Manages and handles component aliases, which is an experimental feature.
+ *
+ * For now, this is an experimental feature to evaluate feasibility, so the implementation is
+ * "quick & dirty". For example, to define aliases, we use a regular intent filter and meta-data
+ * in the manifest, instead of adding proper tags/attributes to AndroidManifest.xml.
+ *
+ * Also, for now, aliases can be defined across any packages, but in the final version, there'll
+ * be restrictions:
+ * - We probably should only allow either privileged or preinstalled apps.
+ * - Aliases can only be defined across packages that are atomically installed, and signed with the
+ *   same key.
+ */
+public class ComponentAliasResolver {
+    private static final String TAG = "ComponentAliasResolver";
+    private static final boolean DEBUG = true;
+
+    private final Object mLock = new Object();
+    private final ActivityManagerService mAm;
+    private final Context mContext;
+
+    @GuardedBy("mLock")
+    private boolean mEnabled;
+
+    @GuardedBy("mLock")
+    private String mOverrideString;
+
+    @GuardedBy("mLock")
+    private final ArrayMap<ComponentName, ComponentName> mFromTo = new ArrayMap<>();
+
+    private static final String ALIAS_FILTER_ACTION = "android.intent.action.EXPERIMENTAL_IS_ALIAS";
+    private static final String META_DATA_ALIAS_TARGET = "alias_target";
+
+    public ComponentAliasResolver(ActivityManagerService service) {
+        mAm = service;
+        mContext = service.mContext;
+    }
+
+    public boolean isEnabled() {
+        synchronized (mLock) {
+            return mEnabled;
+        }
+    }
+
+    /**
+     * When there's any change to packages, we refresh all the aliases.
+     * TODO: In the production version, we should update only the changed package.
+     */
+    final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageModified(String packageName) {
+            refresh();
+        }
+
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            refresh();
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            refresh();
+        }
+    };
+
+    /**
+     * (Re-)loads aliases from <meta-data> and the device config override.
+     */
+    public void update(boolean enabled, String overrides) {
+        synchronized (mLock) {
+            if (enabled == mEnabled && Objects.equals(overrides, mOverrideString)) {
+                return;
+            }
+            if (enabled != mEnabled) {
+                Slog.i(TAG, (enabled ? "Enabling" : "Disabling") + " component aliases...");
+                if (enabled) {
+                    mPackageMonitor.register(mAm.mContext, UserHandle.ALL,
+                            /* externalStorage= */ false, BackgroundThread.getHandler());
+                } else {
+                    mPackageMonitor.unregister();
+                }
+            }
+            mEnabled = enabled;
+            mOverrideString = overrides;
+
+            if (mEnabled) {
+                refreshLocked();
+            } else {
+                mFromTo.clear();
+            }
+        }
+    }
+
+    private void refresh() {
+        synchronized (mLock) {
+            refreshLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void refreshLocked() {
+        if (DEBUG) Slog.d(TAG, "Refreshing aliases...");
+        mFromTo.clear();
+        loadFromMetadataLocked();
+        loadOverridesLocked();
+    }
+
+    /**
+     * Scans all the "alias" components and inserts the from-to pairs to the map.
+     */
+    @GuardedBy("mLock")
+    private void loadFromMetadataLocked() {
+        if (DEBUG) Slog.d(TAG, "Scanning aliases...");
+        Intent i = new Intent(ALIAS_FILTER_ACTION);
+
+        List<ResolveInfo> services = mContext.getPackageManager().queryIntentServicesAsUser(
+                i,
+                PackageManager.MATCH_UNINSTALLED_PACKAGES
+                        | PackageManager.MATCH_ANY_USER
+                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                        | PackageManager.GET_META_DATA,
+                UserHandle.USER_SYSTEM);
+
+        for (ResolveInfo ri : services) {
+            final ComponentInfo ci = ri.getComponentInfo();
+            final ComponentName from = ci.getComponentName();
+            final ComponentName to = ComponentName.unflattenFromString(
+                    ci.metaData.getString(META_DATA_ALIAS_TARGET));
+            if (!validateComponentName(to)) {
+                continue;
+            }
+            if (DEBUG) {
+                Slog.d(TAG, "" + from.flattenToShortString() + " -> " + to.flattenToShortString());
+            }
+            mFromTo.put(from, to);
+        }
+
+        // TODO: Scan for other component types as well.
+    }
+
+    /**
+     * Parses an "override" string and inserts the from-to pairs to the map.
+     *
+     * The format is:
+     * ALIAS-COMPONENT-1 ":" TARGET-COMPONENT-1 ( "," ALIAS-COMPONENT-2 ":" TARGET-COMPONENT-2 )*
+     */
+    @GuardedBy("mLock")
+    private void loadOverridesLocked() {
+        if (DEBUG) Slog.d(TAG, "Loading aliases overrides ...");
+        for (String line : mOverrideString.split("\\,+")) {
+            final String[] fields = line.split("\\:+", 2);
+            final ComponentName from = ComponentName.unflattenFromString(fields[0]);
+            if (!validateComponentName(from)) {
+                continue;
+            }
+
+            if (fields.length == 1) {
+                if (DEBUG) Slog.d(TAG, "" + from.flattenToShortString() + " [removed]");
+                mFromTo.remove(from);
+            } else {
+                final ComponentName to = ComponentName.unflattenFromString(fields[1]);
+                if (!validateComponentName(to)) {
+                    continue;
+                }
+
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "" + from.flattenToShortString() + " -> " + to.flattenToShortString());
+                }
+                mFromTo.put(from, to);
+            }
+        }
+    }
+
+    private boolean validateComponentName(ComponentName cn) {
+        if (cn != null) {
+            return true;
+        }
+        Slog.e(TAG, "Invalid component name detected: " + cn);
+        return false;
+    }
+
+    /**
+     * Dump the aliases for dumpsys / bugrports.
+     */
+    public void dump(PrintWriter pw) {
+        synchronized (mLock) {
+            pw.println("ACTIVITY MANAGER COMPONENT-ALIAS (dumpsys activity component-alias)");
+            pw.print("  Enabled: "); pw.println(mEnabled);
+
+            pw.println("  Aliases:");
+            for (int i = 0; i < mFromTo.size(); i++) {
+                ComponentName from = mFromTo.keyAt(i);
+                ComponentName to = mFromTo.valueAt(i);
+                pw.print("    ");
+                pw.print(from.flattenToShortString());
+                pw.print(" -> ");
+                pw.print(to.flattenToShortString());
+                pw.println();
+            }
+            pw.println();
+        }
+    }
+
+    /**
+     * Contains alias resolution information.
+     */
+    public static class Resolution<T> {
+        /** "From" component. Null if component alias is disabled. */
+        @Nullable
+        public final T source;
+
+        /** "To" component. Null if component alias is disabled, or the source isn't an alias. */
+        @Nullable
+        public final T resolved;
+
+        public Resolution(T source, T resolved) {
+            this.source = source;
+            this.resolved = resolved;
+        }
+
+        @Nullable
+        public boolean isAlias() {
+            return this.resolved != null;
+        }
+
+        @Nullable
+        public T getAlias() {
+            return isAlias() ? source : null;
+        }
+
+        @Nullable
+        public T getTarget() {
+            return isAlias() ? resolved : null;
+        }
+    }
+
+    @Nullable
+    public Resolution<ComponentName> resolveService(
+            @NonNull Intent service, @Nullable String resolvedType,
+            int packageFlags, int userId, int callingUid) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (!mEnabled) {
+                    return new Resolution<>(null, null);
+                }
+
+                PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+
+                ResolveInfo rInfo = pmi.resolveService(service,
+                        resolvedType, packageFlags, userId, callingUid);
+                ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
+                if (sInfo == null) {
+                    return null; // Service not found.
+                }
+                final ComponentName alias =
+                        new ComponentName(sInfo.applicationInfo.packageName, sInfo.name);
+                final ComponentName target = mFromTo.get(alias);
+
+                if (target != null) {
+                    // It's an alias. Keep the original intent, and rewrite it.
+                    service.setOriginalIntent(new Intent(service));
+
+                    service.setPackage(null);
+                    service.setComponent(target);
+
+                    if (DEBUG) {
+                        Slog.d(TAG, "Alias resolved: " + alias.flattenToShortString()
+                                + " -> " + target.flattenToShortString());
+                    }
+                }
+                return new Resolution<>(alias, target);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index e6cd509..b434328 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -18,8 +18,10 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 
+import android.annotation.Nullable;
 import android.app.IServiceConnection;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -47,6 +49,13 @@
     public AssociationState.SourceState association; // Association tracking
     String stringName;              // Caching of toString.
     boolean serviceDead;            // Well is it?
+    private Object mProcStatsLock;  // Internal lock for accessing AssociationState
+    /**
+     * If the connection was made against an alias, then the alias conponent name. Otherwise, null.
+     * We return this component name to the client.
+     */
+    @Nullable
+    final ComponentName aliasComponent;
 
     // Please keep the following two enum list synced.
     private static final int[] BIND_ORIG_ENUMS = new int[] {
@@ -101,7 +110,8 @@
             ActivityServiceConnectionsHolder<ConnectionRecord> _activity,
             IServiceConnection _conn, int _flags,
             int _clientLabel, PendingIntent _clientIntent,
-            int _clientUid, String _clientProcessName, String _clientPackageName) {
+            int _clientUid, String _clientProcessName, String _clientPackageName,
+            ComponentName _aliasComponent) {
         binding = _binding;
         activity = _activity;
         conn = _conn;
@@ -111,6 +121,7 @@
         clientUid = _clientUid;
         clientProcessName = _clientProcessName;
         clientPackageName = _clientPackageName;
+        aliasComponent = _aliasComponent;
     }
 
     public boolean hasFlag(final int flag) {
@@ -137,23 +148,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..d1e56a0 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -72,6 +72,7 @@
 import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -114,6 +115,8 @@
 import com.android.server.wm.WindowProcessController;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -171,6 +174,27 @@
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
     static final long USE_SHORT_FGS_USAGE_INTERACTION_TIME = 183972877L;
 
+    static final int CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY = 0;
+    static final int CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY = 1;
+    static final int CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME = 2;
+
+    @IntDef(prefix = { "CACHED_COMPAT_CHANGE_" }, value = {
+        CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY,
+        CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY,
+        CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    static @interface CachedCompatChangeId{}
+
+    /**
+     * Mapping from CACHED_COMPAT_CHANGE_* to the actual compat change id.
+     */
+    static final long[] CACHED_COMPAT_CHANGE_IDS_MAPPING = new long[] {
+        PROCESS_CAPABILITY_CHANGE_ID,
+        CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID,
+        USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+    };
+
     /**
      * For some direct access we need to power manager.
      */
@@ -396,6 +420,12 @@
         return mPlatformCompatCache;
     }
 
+    boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, ApplicationInfo app,
+            boolean defaultValue) {
+        return getPlatformCompatCache().isChangeEnabled(
+                CACHED_COMPAT_CHANGE_IDS_MAPPING[cachedCompatChangeId], app, defaultValue);
+    }
+
     OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
         this(service, processList, activeUids, createAdjusterThread());
     }
@@ -511,6 +541,7 @@
         }
 
         app.mState.resetCachedInfo();
+        app.mState.setCurBoundByNonBgRestrictedApp(false);
         UidRecord uidRec = app.getUidRecord();
         if (uidRec != null) {
             if (DEBUG_UID_OBSERVERS) {
@@ -644,6 +675,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 +966,7 @@
                 state.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
                 state.setSetCapability(PROCESS_CAPABILITY_NONE);
                 state.resetCachedInfo();
+                state.setCurBoundByNonBgRestrictedApp(false);
             }
         }
         mProcessesInCycle.clear();
@@ -1561,6 +1594,7 @@
         state.resetAllowStartFgsState();
         if (!cycleReEval) {
             // Don't reset this flag when doing cycles re-evaluation.
+            state.setNoKillOnBgRestrictedAndIdle(false);
             app.mOptRecord.setShouldNotFreeze(false);
         }
 
@@ -1900,6 +1934,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
@@ -1957,12 +1992,8 @@
                             (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
                                     != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
 
-                    boolean enabled = false;
-                    try {
-                        enabled = getPlatformCompatCache().isChangeEnabled(
-                                CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
-                    } catch (RemoteException e) {
-                    }
+                    final boolean enabled = state.getCachedCompatChange(
+                            CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY);
                     if (enabled) {
                         capabilityFromFGS |=
                                 (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
@@ -2014,6 +2045,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);
@@ -2179,12 +2215,8 @@
                                 // to client's state.
                                 clientProcState = PROCESS_STATE_BOUND_TOP;
                                 state.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
-                                boolean enabled = false;
-                                try {
-                                    enabled = getPlatformCompatCache().isChangeEnabled(
-                                            PROCESS_CAPABILITY_CHANGE_ID, client.info);
-                                } catch (RemoteException e) {
-                                }
+                                final boolean enabled = cstate.getCachedCompatChange(
+                                        CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY);
                                 if (enabled) {
                                     if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
                                         // TOP process passes all capabilities to the service.
@@ -2336,6 +2368,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 +2551,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,14 +2859,16 @@
                 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);
             }
         } else if (state.hasReportedInteraction()) {
-            final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled(
-                    USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);
+            final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange(
+                    CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME);
             final long interactionThreshold = fgsInteractionChangeEnabled
                     ? mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S
                     : mConstants.USAGE_STATS_INTERACTION_INTERVAL_PRE_S;
@@ -2837,8 +2878,8 @@
                 maybeUpdateUsageStatsLSP(app, nowElapsed);
             }
         } else {
-            final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled(
-                    USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);
+            final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange(
+                    CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME);
             final long interactionThreshold = fgsInteractionChangeEnabled
                     ? mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S
                     : mConstants.SERVICE_USAGE_INTERACTION_TIME_PRE_S;
@@ -2853,6 +2894,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);
@@ -2869,6 +2923,23 @@
                             + " target=" + state.getAdjTarget() + " capability=" + item.capability);
         }
 
+        if (state.isCached() && !state.shouldNotKillOnBgRestrictedAndIdle()) {
+            // It's eligible to get killed when in UID idle and bg restricted mode,
+            // check if these states are just flipped.
+            if (!state.isSetCached() || state.isSetNoKillOnBgRestrictedAndIdle()) {
+                // Take the timestamp, we'd hold the killing for the background settle time
+                // (for states debouncing to avoid from thrashing).
+                state.setLastCanKillOnBgRestrictedAndIdleTime(nowElapsed);
+                // Kick off the delayed checkup message if needed.
+                if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+                    mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+                            mConstants.mKillBgRestrictedAndCachedIdleSettleTimeMs);
+                }
+            }
+        }
+        state.setSetCached(state.isCached());
+        state.setSetNoKillOnBgRestrictedAndIdle(state.shouldNotKillOnBgRestrictedAndIdle());
+
         return success;
     }
 
@@ -2927,8 +2998,8 @@
         if (mService.mUsageStatsService == null) {
             return;
         }
-        final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled(
-                USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);
+        final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange(
+                CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME);
         boolean isInteraction;
         // To avoid some abuse patterns, we are going to be careful about what we consider
         // to be an app interaction.  Being the top activity doesn't count while the display
@@ -3017,6 +3088,20 @@
         if (mLocalPowerManager != null) {
             mLocalPowerManager.finishUidChanges();
         }
+        // Also check if there are any apps in cached and background restricted mode,
+        // if so, kill it if it's been there long enough, or kick off a msg to check
+        // it later.
+        if (mService.mConstants.mKillBgRestrictedAndCachedIdle) {
+            final ArraySet<ProcessRecord> apps = mProcessList.mAppsInBackgroundRestricted;
+            for (int i = 0, size = apps.size(); i < size; i++) {
+                // Check to see if needs to be killed.
+                final long bgTime = mProcessList.killAppIfBgRestrictedAndCachedIdleLocked(
+                        apps.valueAt(i), nowElapsed) - mConstants.BACKGROUND_SETTLE_TIME;
+                if (bgTime > 0 && (nextTime == 0 || nextTime > bgTime)) {
+                    nextTime = bgTime;
+                }
+            }
+        }
         if (nextTime > 0) {
             mService.mHandler.removeMessages(IDLE_UIDS_MSG);
             mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
diff --git a/services/core/java/com/android/server/am/PhantomProcessRecord.java b/services/core/java/com/android/server/am/PhantomProcessRecord.java
index 0156ee5..1a692df 100644
--- a/services/core/java/com/android/server/am/PhantomProcessRecord.java
+++ b/services/core/java/com/android/server/am/PhantomProcessRecord.java
@@ -122,7 +122,7 @@
                     // We'll notify the listener when we're notified it's dead.
                     // Meanwhile, we'd also need handle the case of zombie processes.
                     mKillHandler.postDelayed(mProcKillTimer, this,
-                            ProcessList.PROC_KILL_TIMEOUT);
+                            mService.mConstants.mProcessKillTimeoutMs);
                 }
                 Process.killProcessQuiet(mPid);
                 ProcessList.killProcessGroup(mUid, mPid);
@@ -138,7 +138,7 @@
             synchronized (mLock) {
                 // The process is maybe in either D or Z state.
                 Slog.w(TAG, "Process " + toString() + " is still alive after "
-                        + ProcessList.PROC_KILL_TIMEOUT + "ms");
+                        + mService.mConstants.mProcessKillTimeoutMs + "ms");
                 // Force a cleanup as we can't keep the fd open forever
                 mZombie = true;
                 onProcDied(false);
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 7e79ef5..a32fe02 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -117,6 +117,12 @@
     private ComponentName mErrorReportReceiver;
 
     /**
+     * ANR dialog data used to dismiss any visible ANR dialogs if the app becomes responsive.
+     */
+    @CompositeRWLock({"mService", "mProcLock"})
+    private AppNotRespondingDialog.Data mAnrData;
+
+    /**
      * Optional local handler to be invoked in the process crash.
      */
     @CompositeRWLock({"mService", "mProcLock"})
@@ -209,6 +215,16 @@
         return mDialogController;
     }
 
+    @GuardedBy({"mService", "mProcLock"})
+    void setAnrData(AppNotRespondingDialog.Data data) {
+        mAnrData = data;
+    }
+
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    AppNotRespondingDialog.Data getAnrData() {
+        return mAnrData;
+    }
+
     ProcessErrorStateRecord(ProcessRecord app) {
         mApp = app;
         mService = app.mService;
@@ -265,7 +281,8 @@
             EventLog.writeEvent(EventLogTags.AM_ANR, mApp.userId, pid, mApp.processName,
                     mApp.info.flags, annotation);
 
-            if (mService.mTraceErrorLogger.isAddErrorIdEnabled()) {
+            if (mService.mTraceErrorLogger != null
+                    && mService.mTraceErrorLogger.isAddErrorIdEnabled()) {
                 errorId = mService.mTraceErrorLogger.generateErrorId();
                 mService.mTraceErrorLogger.addErrorIdToTrace(mApp.processName, errorId);
             } else {
@@ -411,7 +428,7 @@
         float loadingProgress = 1;
         IncrementalMetrics incrementalMetrics = null;
         final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal();
-        if (mApp.info != null && mApp.info.packageName != null) {
+        if (mApp.info != null && mApp.info.packageName != null && packageManagerInternal != null) {
             IncrementalStatesInfo incrementalStatesInfo =
                     packageManagerInternal.getIncrementalStatesInfo(
                             mApp.info.packageName, mApp.uid, mApp.userId);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a97738f..cf8be63 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -42,6 +42,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
 import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESS_DIED_UI_MSG;
+import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
 import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_DELAY_MS;
 import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_MSG;
 import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK;
@@ -126,6 +127,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.MemInfoReader;
+import com.android.server.AppStateTracker;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
@@ -360,11 +362,6 @@
     private static final long LMKD_RECONNECT_DELAY_MS = 1000;
 
     /**
-     * How long between a process kill and we actually receive its death recipient
-     */
-    static final int PROC_KILL_TIMEOUT = 2000; // 2 seconds;
-
-    /**
      * Native heap allocations will now have a non-zero tag in the most significant byte.
      * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
      * Pointers</a>
@@ -544,6 +541,12 @@
     final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
             new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
 
+    /**
+     * The list of apps in background restricted mode.
+     */
+    @GuardedBy("mService")
+    final ArraySet<ProcessRecord> mAppsInBackgroundRestricted = new ArraySet<>();
+
     private PlatformCompat mPlatformCompat = null;
 
     /**
@@ -2105,65 +2108,94 @@
             final int[] gids, final int runtimeFlags, int zygotePolicyFlags,
             final int mountExternal, final String requiredAbi, final String instructionSet,
             final String invokeWith, final long startSeq) {
-        // If there is a preceding instance of the process, wait for its death with a timeout.
+        final Runnable startRunnable = () -> {
+            try {
+                final Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),
+                        entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,
+                        mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,
+                        app.getStartTime());
+
+                synchronized (mService) {
+                    handleProcessStartedLocked(app, startResult, startSeq);
+                }
+            } catch (RuntimeException e) {
+                synchronized (mService) {
+                    Slog.e(ActivityManagerService.TAG, "Failure starting process "
+                            + app.processName, e);
+                    mPendingStarts.remove(startSeq);
+                    app.setPendingStart(false);
+                    mService.forceStopPackageLocked(app.info.packageName,
+                            UserHandle.getAppId(app.uid),
+                            false, false, true, false, false, app.userId, "start failure");
+                }
+            }
+        };
         // Use local reference since we are not using locks here
         final ProcessRecord predecessor = app.mPredecessor;
-        int prevPid;
-        if (predecessor != null && (prevPid = predecessor.getDyingPid()) > 0) {
-            long now = System.currentTimeMillis();
-            final long end = now + PROC_KILL_TIMEOUT;
-            final int oldPolicy = StrictMode.getThreadPolicyMask();
-            try {
-                StrictMode.setThreadPolicyMask(0);
-                Process.waitForProcessDeath(prevPid, PROC_KILL_TIMEOUT);
-                // It's killed successfully, but we'd make sure the cleanup work is done.
-                synchronized (predecessor) {
-                    if (app.mPredecessor != null) {
-                        now = System.currentTimeMillis();
-                        if (now < end) {
-                            try {
-                                predecessor.wait(end - now);
-                            } catch (InterruptedException e) {
-                            }
-                            if (System.currentTimeMillis() >= end) {
-                                Slog.w(TAG, predecessor + " " + prevPid
-                                        + " has died but its obituary delivery is slow.");
-                            }
-                        }
-                    }
-                    if (app.mPredecessor != null && app.mPredecessor.getPid() > 0) {
-                        // The cleanup work hasn't be done yet, let's log it and continue.
-                        Slog.w(TAG, predecessor + " " + prevPid
-                                + " has died, but its cleanup isn't done");
-                    }
-                }
-            } catch (Exception e) {
-                // It's still alive... maybe blocked at uninterruptible sleep ?
-                Slog.wtf(TAG, predecessor.toString() + " " + prevPid
-                        + " refused to die, but we need to launch " + app, e);
-            } finally {
-                StrictMode.setThreadPolicyMask(oldPolicy);
+        if (predecessor != null && predecessor.getDyingPid() > 0) {
+            handleProcessStartWithPredecessor(predecessor, startRunnable);
+        } else {
+            // Kick off the process start for real.
+            startRunnable.run();
+        }
+    }
+
+    /**
+     * Handle the case where the given process is killed but still not gone, but we'd need to start
+     * the new instance of it.
+     */
+    private void handleProcessStartWithPredecessor(final ProcessRecord predecessor,
+            final Runnable successorStartRunnable) {
+        // If there is a preceding instance of the process, wait for its death with a timeout.
+        if (predecessor.mSuccessorStartRunnable != null) {
+            // It's been watched already, this shouldn't happen.
+            Slog.wtf(TAG, "We've been watching for the death of " + predecessor);
+            return;
+        }
+        predecessor.mSuccessorStartRunnable = successorStartRunnable;
+        mService.mProcStartHandler.sendMessageDelayed(mService.mProcStartHandler.obtainMessage(
+                ProcStartHandler.MSG_PROCESS_KILL_TIMEOUT, predecessor),
+                mService.mConstants.mProcessKillTimeoutMs);
+    }
+
+    static final class ProcStartHandler extends Handler {
+        static final int MSG_PROCESS_DIED = 1;
+        static final int MSG_PROCESS_KILL_TIMEOUT = 2;
+
+        private final ActivityManagerService mService;
+
+        ProcStartHandler(ActivityManagerService service, Looper looper) {
+            super(looper);
+            mService = service;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PROCESS_DIED:
+                    mService.mProcessList.handlePredecessorProcDied((ProcessRecord) msg.obj);
+                    break;
+                case MSG_PROCESS_KILL_TIMEOUT:
+                    mService.handleProcessStartOrKillTimeoutLocked((ProcessRecord) msg.obj,
+                            /* isKillTimeout */ true);
+                    break;
             }
         }
-        try {
-            final Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),
-                    entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,
-                    mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,
-                    app.getStartTime());
+    }
 
-            synchronized (mService) {
-                handleProcessStartedLocked(app, startResult, startSeq);
-            }
-        } catch (RuntimeException e) {
-            synchronized (mService) {
-                Slog.e(ActivityManagerService.TAG, "Failure starting process "
-                        + app.processName, e);
-                mPendingStarts.remove(startSeq);
-                app.setPendingStart(false);
-                mService.forceStopPackageLocked(app.info.packageName,
-                        UserHandle.getAppId(app.uid),
-                        false, false, true, false, false, app.userId, "start failure");
-            }
+    /**
+     * Called when the dying process we're waiting for is really gone.
+     */
+    private void handlePredecessorProcDied(ProcessRecord app) {
+        if (DEBUG_PROCESSES) {
+            Slog.i(TAG, app.toString() + " is really gone now");
+        }
+
+        // Now kick off the subsequent process start if there is any.
+        final Runnable start = app.mSuccessorStartRunnable;
+        if (start != null) {
+            app.mSuccessorStartRunnable = null;
+            start.run();
         }
     }
 
@@ -2370,6 +2402,16 @@
                 allowlistedAppDataInfoMap = null;
             }
 
+            AppStateTracker ast = mService.mServices.mAppStateTracker;
+            if (ast != null) {
+                final boolean inBgRestricted = ast.isAppBackgroundRestricted(
+                        app.info.uid, app.info.packageName);
+                if (inBgRestricted) {
+                    mAppsInBackgroundRestricted.add(app);
+                }
+                app.mState.setBackgroundRestricted(inBgRestricted);
+            }
+
             final Process.ProcessStartResult startResult;
             boolean regularZygote = false;
             if (hostingRecord.usesWebviewZygote()) {
@@ -3104,6 +3146,7 @@
         if (record != null && record.appZygote) {
             removeProcessFromAppZygoteLocked(record);
         }
+        mAppsInBackgroundRestricted.remove(record);
 
         return old;
     }
@@ -4982,10 +5025,10 @@
             // App has been removed already, meaning cleanup has done.
             Slog.v(TAG, "Got obituary of " + pid + ":" + app.processName);
             app.unlinkDeathRecipient();
-            handlePrecedingAppDiedLocked(app);
             // It's really gone now, let's remove from the dying process list.
             mDyingProcesses.remove(app.processName, app.uid);
             app.setDyingPid(0);
+            handlePrecedingAppDiedLocked(app);
             return true;
         }
         return false;
@@ -4998,27 +5041,98 @@
      */
     @GuardedBy("mService")
     boolean handlePrecedingAppDiedLocked(ProcessRecord app) {
-        synchronized (app) {
-            if (app.mSuccessor != null) {
-                // We don't allow restart with this ProcessRecord now,
-                // because we have created a new one already.
-                // If it's persistent, add the successor to mPersistentStartingProcesses
-                if (app.isPersistent() && !app.isRemoved()) {
-                    if (mService.mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) {
-                        mService.mPersistentStartingProcesses.add(app.mSuccessor);
-                    }
+        if (app.mSuccessor != null) {
+            // We don't allow restart with this ProcessRecord now,
+            // because we have created a new one already.
+            // If it's persistent, add the successor to mPersistentStartingProcesses
+            if (app.isPersistent() && !app.isRemoved()) {
+                if (mService.mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) {
+                    mService.mPersistentStartingProcesses.add(app.mSuccessor);
                 }
-                // clean up the field so the successor's proc starter could proceed.
-                app.mSuccessor.mPredecessor = null;
-                app.mSuccessor = null;
-                // Notify if anyone is waiting for it.
-                app.notifyAll();
-                return false;
             }
+            // clean up the field so the successor's proc starter could proceed.
+            app.mSuccessor.mPredecessor = null;
+            app.mSuccessor = null;
+            // Remove any pending timeout msg.
+            mService.mProcStartHandler.removeMessages(
+                    ProcStartHandler.MSG_PROCESS_KILL_TIMEOUT, app);
+            // Kick off the proc start for the succeeding instance
+            mService.mProcStartHandler.obtainMessage(
+                    ProcStartHandler.MSG_PROCESS_DIED, app).sendToTarget();
+            return false;
         }
         return true;
     }
 
+    @GuardedBy("mService")
+    void updateBackgroundRestrictedForUidPackageLocked(int uid, String packageName,
+            boolean restricted) {
+        final UidRecord uidRec = getUidRecordLOSP(uid);
+        if (uidRec != null) {
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            uidRec.forEachProcess(app -> {
+                if (TextUtils.equals(app.info.packageName, packageName)) {
+                    app.mState.setBackgroundRestricted(restricted);
+                    if (restricted) {
+                        mAppsInBackgroundRestricted.add(app);
+                        final long future = killAppIfBgRestrictedAndCachedIdleLocked(
+                                app, nowElapsed);
+                        if (future > 0 && !mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+                            mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+                                    future - nowElapsed);
+                        }
+                    } else {
+                        mAppsInBackgroundRestricted.remove(app);
+                    }
+                    if (!app.isKilledByAm()) {
+                        mService.enqueueOomAdjTargetLocked(app);
+                    }
+                }
+            });
+            /* Will be a no-op if nothing pending */
+            mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        }
+    }
+
+    /**
+     * Kill the given app if it's in cached idle and background restricted mode.
+     *
+     * @return A future timestamp when the app should be killed at, or a 0 if it shouldn't
+     * be killed or it has been killed.
+     */
+    @GuardedBy("mService")
+    long killAppIfBgRestrictedAndCachedIdleLocked(ProcessRecord app, long nowElapsed) {
+        final UidRecord uidRec = app.getUidRecord();
+        final long lastCanKillTime = app.mState.getLastCanKillOnBgRestrictedAndIdleTime();
+        if (!mService.mConstants.mKillBgRestrictedAndCachedIdle
+                || app.isKilled() || app.getThread() == null || uidRec == null || !uidRec.isIdle()
+                || !app.isCached() || app.mState.shouldNotKillOnBgRestrictedAndIdle()
+                || !app.mState.isBackgroundRestricted() || lastCanKillTime == 0) {
+            return 0;
+        }
+        final long future = lastCanKillTime
+                + mService.mConstants.mKillBgRestrictedAndCachedIdleSettleTimeMs;
+        if (future <= nowElapsed) {
+            app.killLocked("cached idle & background restricted",
+                    ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY,
+                    true);
+            return 0;
+        }
+        return future;
+    }
+
+    /**
+     * Called by {@link ActivityManagerService#enqueueUidChangeLocked} only, it doesn't schedule
+     * the standy killing checks because it should have been scheduled before enqueueing UID idle
+     * changed.
+     */
+    @GuardedBy("mService")
+    void killAppIfBgRestrictedAndCachedIdleLocked(UidRecord uidRec) {
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        uidRec.forEachProcess(app -> killAppIfBgRestrictedAndCachedIdleLocked(app, nowElapsed));
+    }
+
     /**
      * Called by ActivityManagerService when a process died.
      */
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 9e94d4a..c573615 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -364,6 +364,13 @@
      */
     volatile ProcessRecord mSuccessor;
 
+    /**
+     * The routine to start its successor process.
+     *
+     * <p>Note: It should be accessed from process start thread only.</p>
+     */
+    Runnable mSuccessorStartRunnable;
+
     void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
             long startTime) {
         this.mStartUid = startUid;
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index dc6bcd8..c4ce873 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -21,6 +21,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.OomAdjuster.CachedCompatChangeId;
 import static com.android.server.am.ProcessRecord.TAG;
 
 import android.annotation.ElapsedRealtimeLong;
@@ -302,6 +303,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")
@@ -342,6 +360,20 @@
     private int mCacheOomRankerUseCount;
 
     /**
+     * Process memory usage (RSS).
+     *
+     * Periodically populated by {@code CacheOomRanker}, stored in this object to cache the values.
+     */
+    @GuardedBy("mService")
+    private long mCacheOomRankerRss;
+
+    /**
+     * The last time, in milliseconds since boot, since {@link #mCacheOomRankerRss} was updated.
+     */
+    @GuardedBy("mService")
+    private long mCacheOomRankerRssTimeMs;
+
+    /**
      * Whether or not this process is reachable from given process.
      */
     @GuardedBy("mService")
@@ -357,6 +389,34 @@
     @ElapsedRealtimeLong
     private long mLastInvisibleTime;
 
+    /**
+     * Whether or not this process could be killed when it's in background restricted mode
+     * and cached &amp; idle state.
+     */
+    @GuardedBy("mService")
+    private boolean mNoKillOnBgRestrictedAndIdle;
+
+    /**
+     * Last set value of {@link #mCached}.
+     */
+    @GuardedBy("mService")
+    private boolean mSetCached;
+
+    /**
+     * Last set value of {@link #mNoKillOnBgRestrictedAndIdle}.
+     */
+    @GuardedBy("mService")
+    private boolean mSetNoKillOnBgRestrictedAndIdle;
+
+    /**
+     * The last time when the {@link #mNoKillOnBgRestrictedAndIdle} is false and the
+     * {@link #mCached} is true, and either the former state is flipping from true to false
+     * when latter state is true, or the latter state is flipping from false to true when the
+     * former state is false.
+     */
+    @GuardedBy("mService")
+    private @ElapsedRealtimeLong long mLastCanKillOnBgRestrictedAndIdleTime;
+
     // Below are the cached task info for OomAdjuster only
     private static final int VALUE_INVALID = -1;
     private static final int VALUE_FALSE = 0;
@@ -377,6 +437,16 @@
     @GuardedBy("mService")
     private int mCachedIsReceivingBroadcast = VALUE_INVALID;
 
+    /**
+     * Cache the return value of PlatformCompat.isChangeEnabled().
+     */
+    @GuardedBy("mService")
+    private int[] mCachedCompatChanges = new int[] {
+        VALUE_INVALID, // CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY
+        VALUE_INVALID, // CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY
+        VALUE_INVALID, // CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME
+    };
+
     @GuardedBy("mService")
     private int mCachedAdj = ProcessList.INVALID_ADJ;
     @GuardedBy("mService")
@@ -566,6 +636,10 @@
 
     @GuardedBy({"mService", "mProcLock"})
     void setSetProcState(int setProcState) {
+        if (ActivityManager.isProcStateCached(mSetProcState)
+                && !ActivityManager.isProcStateCached(setProcState)) {
+            mCacheOomRankerUseCount++;
+        }
         mSetProcState = setProcState;
     }
 
@@ -829,12 +903,7 @@
 
     @GuardedBy("mService")
     void setCached(boolean cached) {
-        if (mCached != cached) {
-            mCached = cached;
-            if (cached) {
-                ++mCacheOomRankerUseCount;
-            }
-        }
+        mCached = cached;
     }
 
     @GuardedBy("mService")
@@ -1009,6 +1078,16 @@
     }
 
     @GuardedBy("mService")
+    boolean getCachedCompatChange(@CachedCompatChangeId int cachedCompatChangeId) {
+        if (mCachedCompatChanges[cachedCompatChangeId] == VALUE_INVALID) {
+            mCachedCompatChanges[cachedCompatChangeId] = mService.mOomAdjuster
+                    .isChangeEnabled(cachedCompatChangeId, mApp.info, false /* default */)
+                    ? VALUE_TRUE : VALUE_FALSE;
+        }
+        return mCachedCompatChanges[cachedCompatChangeId] == VALUE_TRUE;
+    }
+
+    @GuardedBy("mService")
     void computeOomAdjFromActivitiesIfNecessary(OomAdjuster.ComputeOomAdjWindowCallback callback,
             int adj, boolean foregroundActivities, boolean hasVisibleActivities, int procState,
             int schedGroup, int appUid, int logUid, int processCurTop) {
@@ -1088,6 +1167,9 @@
         mCurSchedGroup = mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
         mCurProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState =
                 PROCESS_STATE_NONEXISTENT;
+        for (int i = 0; i < mCachedCompatChanges.length; i++) {
+            mCachedCompatChanges[i] = VALUE_INVALID;
+        }
     }
 
     @GuardedBy("mService")
@@ -1113,6 +1195,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;
@@ -1127,6 +1239,62 @@
         return mLastInvisibleTime;
     }
 
+    @GuardedBy("mService")
+    void setNoKillOnBgRestrictedAndIdle(boolean shouldNotKill) {
+        mNoKillOnBgRestrictedAndIdle = shouldNotKill;
+    }
+
+    @GuardedBy("mService")
+    boolean shouldNotKillOnBgRestrictedAndIdle() {
+        return mNoKillOnBgRestrictedAndIdle;
+    }
+
+    @GuardedBy("mService")
+    void setSetCached(boolean cached) {
+        mSetCached = cached;
+    }
+
+    @GuardedBy("mService")
+    boolean isSetCached() {
+        return mSetCached;
+    }
+
+    @GuardedBy("mService")
+    void setSetNoKillOnBgRestrictedAndIdle(boolean shouldNotKill) {
+        mSetNoKillOnBgRestrictedAndIdle = shouldNotKill;
+    }
+
+    @GuardedBy("mService")
+    boolean isSetNoKillOnBgRestrictedAndIdle() {
+        return mSetNoKillOnBgRestrictedAndIdle;
+    }
+
+    @GuardedBy("mService")
+    void setLastCanKillOnBgRestrictedAndIdleTime(@ElapsedRealtimeLong long now) {
+        mLastCanKillOnBgRestrictedAndIdleTime = now;
+    }
+
+    @ElapsedRealtimeLong
+    @GuardedBy("mService")
+    long getLastCanKillOnBgRestrictedAndIdleTime() {
+        return mLastCanKillOnBgRestrictedAndIdleTime;
+    }
+
+    public void setCacheOomRankerRss(long rss, long rssTimeMs) {
+        mCacheOomRankerRss = rss;
+        mCacheOomRankerRssTimeMs = rssTimeMs;
+    }
+
+    @GuardedBy("mService")
+    public long getCacheOomRankerRss() {
+        return mCacheOomRankerRss;
+    }
+
+    @GuardedBy("mService")
+    public long getCacheOomRankerRssTimeMs() {
+        return mCacheOomRankerRssTimeMs;
+    }
+
     @GuardedBy({"mService", "mProcLock"})
     void dump(PrintWriter pw, String prefix, long nowUptime) {
         if (mReportedInteraction || mFgInteractionTime != 0) {
@@ -1164,7 +1332,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/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index fa7eae3..256c472 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -594,7 +594,8 @@
 
             final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
             t.traceBegin("UM.onBeforeUnlockUser-" + userId);
-            mInjector.getUserManager().onBeforeUnlockUser(userId);
+            final ArraySet<String> reconciledPackages =
+                    mInjector.getUserManager().onBeforeUnlockUser(userId);
             t.traceEnd();
             synchronized (mLock) {
                 // Do not proceed if unexpected state
@@ -603,6 +604,9 @@
                 }
             }
             mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+            t.traceBegin("UM.onUserStateRunningUnlocking-" + userId);
+            mInjector.getUserManager().onUserStateRunningUnlocking(userId, reconciledPackages);
+            t.traceEnd();
 
             uss.mUnlockProgress.setProgress(20);
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 8961a5a..84a3060 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -632,6 +632,37 @@
         sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
     }
 
+    private static final class LeAudioDeviceConnectionInfo {
+        final @NonNull BluetoothDevice mDevice;
+        final @AudioService.BtProfileConnectionState int mState;
+        final boolean mSupprNoisy;
+        final @NonNull String mEventSource;
+
+        LeAudioDeviceConnectionInfo(@NonNull BluetoothDevice device,
+                @AudioService.BtProfileConnectionState int state,
+                boolean suppressNoisyIntent, @NonNull String eventSource) {
+            mDevice = device;
+            mState = state;
+            mSupprNoisy = suppressNoisyIntent;
+            mEventSource = eventSource;
+        }
+    }
+
+    /*package*/ void postBluetoothLeAudioOutDeviceConnectionState(
+            @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+            boolean suppressNoisyIntent, @NonNull String eventSource) {
+        final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
+                device, state, suppressNoisyIntent, eventSource);
+        sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
+    }
+
+    /*package*/ void postBluetoothLeAudioInDeviceConnectionState(
+            @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+            @NonNull String eventSource) {
+        final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
+                device, state, false, eventSource);
+        sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
+    }
 
     /**
      * Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
@@ -902,6 +933,23 @@
                 delay);
     }
 
+    /*package*/ void postSetLeAudioOutConnectionState(
+            @AudioService.BtProfileConnectionState int state,
+            @NonNull BluetoothDevice device, int delay) {
+        sendILMsg(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE, SENDMSG_QUEUE,
+                state,
+                device,
+                delay);
+    }
+
+    /*package*/ void postSetLeAudioInConnectionState(
+            @AudioService.BtProfileConnectionState int state,
+            @NonNull BluetoothDevice device) {
+        sendILMsgNoDelay(MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE, SENDMSG_QUEUE,
+                state,
+                device);
+    }
+
     /*package*/ void postDisconnectA2dp() {
         sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
     }
@@ -1223,7 +1271,20 @@
                     synchronized (mDeviceStateLock) {
                         mDeviceInventory.onSetHearingAidConnectionState(
                                 (BluetoothDevice) msg.obj, msg.arg1,
-                                mAudioService.getHearingAidStreamType());
+                                mAudioService.getBluetoothContextualVolumeStream());
+                    }
+                    break;
+                case MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE:
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onSetLeAudioOutConnectionState(
+                                (BluetoothDevice) msg.obj, msg.arg1,
+                                mAudioService.getBluetoothContextualVolumeStream());
+                    }
+                    break;
+                case MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE:
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onSetLeAudioInConnectionState(
+                                (BluetoothDevice) msg.obj, msg.arg1);
                     }
                     break;
                 case MSG_BT_HEADSET_CNCT_FAILED:
@@ -1415,6 +1476,31 @@
                     final int capturePreset = msg.arg1;
                     mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
                 } break;
+                case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT: {
+                    final LeAudioDeviceConnectionInfo info =
+                            (LeAudioDeviceConnectionInfo) msg.obj;
+                    AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                            "setLeAudioDeviceOutConnectionState state=" + info.mState
+                                    + " addr=" + info.mDevice.getAddress()
+                                    + " supprNoisy=" + info.mSupprNoisy
+                                    + " src=" + info.mEventSource)).printLog(TAG));
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.setBluetoothLeAudioOutDeviceConnectionState(
+                                info.mDevice, info.mState, info.mSupprNoisy);
+                    }
+                } break;
+                case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT: {
+                    final LeAudioDeviceConnectionInfo info =
+                            (LeAudioDeviceConnectionInfo) msg.obj;
+                    AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                            "setLeAudioDeviceInConnectionState state=" + info.mState
+                                    + " addr=" + info.mDevice.getAddress()
+                                    + " src=" + info.mEventSource)).printLog(TAG));
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.setBluetoothLeAudioInDeviceConnectionState(info.mDevice,
+                                info.mState);
+                    }
+                } break;
                 default:
                     Log.wtf(TAG, "Invalid message " + msg.what);
             }
@@ -1496,6 +1582,11 @@
     private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
     private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
 
+    private static final int MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE = 42;
+    private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43;
+    private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44;
+    private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
+
     private static boolean isMessageHandledUnderWakelock(int msgId) {
         switch(msgId) {
             case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
@@ -1511,6 +1602,8 @@
             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
             case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
             case MSG_CHECK_MUTE_MUSIC:
+            case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT:
+            case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT:
                 return true;
             default:
                 return false;
@@ -1719,11 +1812,10 @@
         if (client == null) {
             return;
         }
-        Log.w(TAG, "Speaker client died");
-        if (removeCommunicationRouteClient(client.getBinder(), false)
-                != null) {
-            onUpdateCommunicationRoute("onCommunicationRouteClientDied");
-        }
+        Log.w(TAG, "Communication client died");
+        setCommunicationRouteForClient(
+                client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED,
+                "onCommunicationRouteClientDied");
     }
 
     /**
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 5944a63..64e620e 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.content.Intent;
 import android.media.AudioDeviceAttributes;
@@ -421,6 +422,45 @@
         }
     }
 
+    /*package*/ void onSetLeAudioConnectionState(BluetoothDevice btDevice,
+                @AudioService.BtProfileConnectionState int state, int streamType, int device) {
+        String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
+        AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                "onSetLeAudioConnectionState addr=" + address));
+
+        synchronized (mDevicesLock) {
+            DeviceInfo di = null;
+            boolean isConnected = false;
+
+            String key = DeviceInfo.makeDeviceListKey(device, btDevice.getAddress());
+            di = mConnectedDevices.get(key);
+            isConnected = di != null;
+
+            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+                makeLeAudioDeviceUnavailable(address, device);
+            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+                makeLeAudioDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
+                        device, "onSetLeAudioConnectionState");
+            }
+        }
+    }
+
+    /*package*/ void onSetLeAudioOutConnectionState(BluetoothDevice btDevice,
+                @AudioService.BtProfileConnectionState int state, int streamType) {
+        // TODO: b/198610537 clarify DEVICE_OUT_BLE_HEADSET vs DEVICE_OUT_BLE_SPEAKER criteria
+        onSetLeAudioConnectionState(btDevice, state, streamType,
+                AudioSystem.DEVICE_OUT_BLE_HEADSET);
+    }
+
+    /*package*/ void onSetLeAudioInConnectionState(BluetoothDevice btDevice,
+                @AudioService.BtProfileConnectionState int state) {
+        onSetLeAudioConnectionState(btDevice, state, AudioSystem.STREAM_DEFAULT,
+                AudioSystem.DEVICE_IN_BLE_HEADSET);
+    }
+
     @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
         /*package*/ void onBluetoothA2dpActiveDeviceChange(
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
@@ -946,6 +986,28 @@
         }
     }
 
+    /*package*/ int setBluetoothLeAudioOutDeviceConnectionState(
+            @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+            boolean suppressNoisyIntent) {
+        synchronized (mDevicesLock) {
+            /* Active device become null and it's previous device is not connected anymore */
+            int delay = 0;
+            if (!suppressNoisyIntent) {
+                int intState = (state == BluetoothLeAudio.STATE_CONNECTED) ? 1 : 0;
+                delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLE_HEADSET,
+                        intState, AudioSystem.DEVICE_NONE);
+            }
+            mDeviceBroker.postSetLeAudioOutConnectionState(state, device, delay);
+            return delay;
+        }
+    }
+
+    /*package*/ void setBluetoothLeAudioInDeviceConnectionState(
+            @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state) {
+        synchronized (mDevicesLock) {
+            mDeviceBroker.postSetLeAudioInConnectionState(state, device);
+        }
+    }
 
     //-------------------------------------------------------------------
     // Internal utilities
@@ -1118,6 +1180,36 @@
     }
 
     @GuardedBy("mDevicesLock")
+    private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
+            String eventSource) {
+        if (device != AudioSystem.DEVICE_NONE) {
+            AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
+                    address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
+            mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
+                    new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+            mDeviceBroker.postAccessoryPlugMediaUnmute(device);
+        }
+
+        if (streamType == AudioSystem.STREAM_DEFAULT) {
+            // No need to update volume for input devices
+            return;
+        }
+
+        mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
+    }
+
+    @GuardedBy("mDevicesLock")
+    private void makeLeAudioDeviceUnavailable(String address, int device) {
+        if (device != AudioSystem.DEVICE_NONE) {
+            AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                    address, "", AudioSystem.AUDIO_FORMAT_DEFAULT);
+            mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
+        }
+
+        setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
+    }
+
+    @GuardedBy("mDevicesLock")
     private void setCurrentAudioRouteNameIfPossible(String name, boolean fromA2dp) {
         synchronized (mCurAudioRoutes) {
             if (TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
@@ -1153,6 +1245,7 @@
         BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
         BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
         BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+        BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
     }
 
     // must be called before removing the device from mConnectedDevices
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index fcd198e..d12cf70 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -94,11 +94,13 @@
 import android.media.IPlaybackConfigDispatcher;
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
+import android.media.ISpatializerCallback;
 import android.media.IStrategyPreferredDevicesDispatcher;
 import android.media.IVolumeController;
 import android.media.MediaMetrics;
 import android.media.MediaRecorder.AudioSource;
 import android.media.PlayerBase;
+import android.media.Spatializer;
 import android.media.VolumePolicy;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
@@ -738,6 +740,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 +1346,9 @@
             updateAssistantUId(true);
             AudioSystem.setRttEnabled(mRttEnabled);
         }
+        synchronized (mHotwordDetectionServiceUidLock) {
+            AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+        }
         synchronized (mAccessibilityServiceUidsLock) {
             AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
         }
@@ -2815,8 +2825,9 @@
         if (uid == android.os.Process.SYSTEM_UID) {
             uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
         }
-        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid,
-                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+        // validate calling package and app op
+        if (!checkNoteAppOp(
+                STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage, attributionTag)) {
             return;
         }
 
@@ -2945,7 +2956,7 @@
             if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                 // only modify the hearing aid attenuation when the stream to modify matches
                 // the one expected by the hearing aid
-                if (streamType == getHearingAidStreamType()) {
+                if (streamType == getBluetoothContextualVolumeStream()) {
                     if (DEBUG_VOL) {
                         Log.d(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index="
                                 + newIndex + " stream=" + streamType);
@@ -3284,11 +3295,11 @@
         }
     }
 
-    /*package*/ int getHearingAidStreamType() {
-        return getHearingAidStreamType(mMode.get());
+    /*package*/ int getBluetoothContextualVolumeStream() {
+        return getBluetoothContextualVolumeStream(mMode.get());
     }
 
-    private int getHearingAidStreamType(int mode) {
+    private int getBluetoothContextualVolumeStream(int mode) {
         switch (mode) {
             case AudioSystem.MODE_IN_COMMUNICATION:
             case AudioSystem.MODE_IN_CALL:
@@ -3445,7 +3456,7 @@
     }
 
     private void updateHearingAidVolumeOnVoiceActivityUpdate() {
-        final int streamType = getHearingAidStreamType();
+        final int streamType = getBluetoothContextualVolumeStream();
         final int index = getStreamVolume(streamType);
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
                 mVoicePlaybackActive.get(), streamType, index));
@@ -3477,7 +3488,7 @@
                 return;
         }
 
-        int streamType = getHearingAidStreamType(newMode);
+        int streamType = getBluetoothContextualVolumeStream(newMode);
 
         final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet(
                 mAudioSystem.getDevicesForStream(streamType));
@@ -3526,8 +3537,8 @@
         if (uid == android.os.Process.SYSTEM_UID) {
             uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
         }
-        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid,
-                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+        if (!checkNoteAppOp(
+                STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage, attributionTag)) {
             return;
         }
 
@@ -3560,7 +3571,7 @@
             }
 
             if (device == AudioSystem.DEVICE_OUT_HEARING_AID
-                    && streamType == getHearingAidStreamType()) {
+                    && streamType == getBluetoothContextualVolumeStream()) {
                 Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
                         + " stream=" + streamType);
                 mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
@@ -3946,8 +3957,8 @@
             uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
         }
         // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
-        if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid,
-                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+        if (!mute && !checkNoteAppOp(
+                AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage, attributionTag)) {
             return;
         }
         if (userId != UserHandle.getCallingUserId() &&
@@ -4080,8 +4091,8 @@
                         ? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE);
 
         // If OP_MUTE_MICROPHONE is set, disallow unmuting.
-        if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid,
-                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+        if (!on && !checkNoteAppOp(
+                AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage, attributionTag)) {
             mmi.set(MediaMetrics.Property.EARLY_RETURN, "disallow unmuting").record();
             return;
         }
@@ -5260,6 +5271,10 @@
     // TODO investigate internal users due to deprecation of SDK API
     /** @see AudioManager#setBluetoothA2dpOn(boolean) */
     public void setBluetoothA2dpOn(boolean on) {
+        if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) {
+            return;
+        }
+
         // for logging only
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
@@ -5285,6 +5300,10 @@
 
     /** @see AudioManager#startBluetoothSco() */
     public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+        if (!checkAudioSettingsPermission("startBluetoothSco()")) {
+            return;
+        }
+
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
         final int scoAudioMode =
@@ -5307,6 +5326,10 @@
 
     /** @see AudioManager#startBluetoothScoVirtualCall() */
     public void startBluetoothScoVirtualCall(IBinder cb) {
+        if (!checkAudioSettingsPermission("startBluetoothScoVirtualCall()")) {
+            return;
+        }
+
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
         final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()")
@@ -6220,6 +6243,38 @@
                 device, state, suppressNoisyIntent, musicDevice, "AudioService");
     }
 
+    private void setBluetoothLeAudioDeviceConnectionState(@NonNull BluetoothDevice device,
+            @BtProfileConnectionState int state) {
+        if (device == null) {
+            throw new IllegalArgumentException("Illegal null device");
+        }
+        if (state != BluetoothProfile.STATE_CONNECTED
+                && state != BluetoothProfile.STATE_DISCONNECTED) {
+            throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
+                    + " (dis)connection, got " + state);
+        }
+    }
+
+    /**
+     * See AudioManager.setBluetoothLeAudioOutDeviceConnectionState()
+     */
+    public void setBluetoothLeAudioOutDeviceConnectionState(
+            @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
+            boolean suppressNoisyIntent) {
+        setBluetoothLeAudioDeviceConnectionState(device, state);
+        mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(device, state,
+                suppressNoisyIntent, "AudioService");
+    }
+
+    /**
+     * See AudioManager.setBluetoothLeAudioInDeviceConnectionState()
+     */
+    public void setBluetoothLeAudioInDeviceConnectionState(
+            @NonNull BluetoothDevice device, @BtProfileConnectionState int state) {
+        setBluetoothLeAudioDeviceConnectionState(device, state);
+        mDeviceBroker.postBluetoothLeAudioInDeviceConnectionState(device, state, "AudioService");
+    }
+
     /**
      * See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
      */
@@ -8194,6 +8249,80 @@
     }
 
     //==========================================================================================
+    private final SpatializerHelper mSpatializerHelper = new SpatializerHelper();
+
+    private void enforceModifyDefaultAudioEffectsPermission() {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Missing MODIFY_DEFAULT_AUDIO_EFFECTS permission");
+        }
+    }
+
+    /** @see AudioManager#getSpatializerImmersiveAudioLevel() */
+    public int getSpatializerImmersiveAudioLevel() {
+        return mSpatializerHelper.getImmersiveAudioLevel();
+    }
+
+    /** @see Spatializer#isEnabled() */
+    public boolean isSpatializerEnabled() {
+        return mSpatializerHelper.isEnabled();
+    }
+
+    /** @see Spatializer#isAvailable() */
+    public boolean isSpatializerAvailable() {
+        return mSpatializerHelper.isAvailable();
+    }
+
+    /** @see Spatializer#setSpatializerEnabled(boolean) */
+    public void setSpatializerEnabled(boolean enabled) {
+        enforceModifyDefaultAudioEffectsPermission();
+        mSpatializerHelper.setEnabled(enabled);
+    }
+
+    /** @see Spatializer#canBeSpatialized() */
+    public boolean canBeSpatialized(
+            @NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
+        Objects.requireNonNull(attributes);
+        Objects.requireNonNull(format);
+        return mSpatializerHelper.canBeSpatialized(attributes, format);
+    }
+
+    /** @see Spatializer.SpatializerInfoDispatcherStub */
+    public void registerSpatializerCallback(
+            @NonNull ISpatializerCallback dispatcher) {
+        Objects.requireNonNull(dispatcher);
+        mSpatializerHelper.registerStateCallback(dispatcher);
+    }
+
+    /** @see Spatializer.SpatializerInfoDispatcherStub */
+    public void unregisterSpatializerCallback(
+            @NonNull ISpatializerCallback dispatcher) {
+        Objects.requireNonNull(dispatcher);
+        mSpatializerHelper.unregisterStateCallback(dispatcher);
+    }
+
+    /** @see Spatializer#getSpatializerCompatibleAudioDevices() */
+    public @NonNull List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices() {
+        enforceModifyAudioRoutingPermission();
+        return mSpatializerHelper.getCompatibleAudioDevices();
+    }
+
+    /** @see Spatializer#addSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */
+    public void addSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+        enforceModifyDefaultAudioEffectsPermission();
+        Objects.requireNonNull(ada);
+        mSpatializerHelper.addCompatibleAudioDevice(ada);
+    }
+
+    /** @see Spatializer#removeSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */
+    public void removeSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+        enforceModifyDefaultAudioEffectsPermission();
+        Objects.requireNonNull(ada);
+        mSpatializerHelper.removeCompatibleAudioDevice(ada);
+    }
+
+    //==========================================================================================
     private boolean readCameraSoundForced() {
         return SystemProperties.getBoolean("audio.camerasound.force", false) ||
                 mContext.getResources().getBoolean(
@@ -9082,6 +9211,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) {
@@ -10478,4 +10617,32 @@
         }
         mFullVolumeDevices.remove(audioSystemDeviceOut);
     }
+
+    //====================
+    // Helper functions for app ops
+    //====================
+    /**
+     * Validates, and notes an app op for a given uid and package name.
+     * Validation comes from exception catching: a security exception indicates the package
+     * doesn't exist, an IAE indicates the uid and package don't match. The code only checks
+     * if exception was thrown for robustness to code changes in op validation
+     * @param op the app op to check
+     * @param uid the uid of the caller
+     * @param packageName the package to check
+     * @return true if the origin of the call is valid (no uid / package mismatch) and the caller
+     *      is allowed to perform the operation
+     */
+    private boolean checkNoteAppOp(int op, int uid, String packageName, String attributionTag) {
+        try {
+            if (mAppOps.noteOp(op, uid, packageName, attributionTag, null)
+                    != AppOpsManager.MODE_ALLOWED) {
+                return false;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error noting op:" + op + " on uid:" + uid + " for package:"
+                    + packageName, e);
+            return false;
+        }
+        return true;
+    }
 }
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/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
index ad72166..872b1fe 100644
--- a/services/core/java/com/android/server/audio/RotationHelper.java
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -21,20 +21,26 @@
 import android.media.AudioSystem;
 import android.os.Handler;
 import android.util.Log;
+import android.view.Display;
 import android.view.Surface;
 import android.view.WindowManager;
 
 /**
  * Class to handle device rotation events for AudioService, and forward device rotation
- * to the audio HALs through AudioSystem.
+ * and current active ID to the audio HALs through AudioSystem.
  *
  * The role of this class is to monitor device orientation changes, and upon rotation,
  * verify the UI orientation. In case of a change, send the new orientation, in increments
  * of 90deg, through AudioSystem.
  *
+ * Another role of this class is to track current active display ID changes. In case of a
+ * change, send the new active display ID through AudioSystem.
+ *
  * Note that even though we're responding to device orientation events, we always
  * query the display rotation so audio stays in sync with video/dialogs. This is
  * done with .getDefaultDisplay().getRotation() from WINDOW_SERVICE.
+ *
+ * We also monitor current display ID and audio is able to know which display is active.
  */
 class RotationHelper {
 
@@ -43,7 +49,9 @@
     private static AudioDisplayListener sDisplayListener;
 
     private static final Object sRotationLock = new Object();
+    private static final Object sActiveDisplayLock = new Object();
     private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock
+    private static int sDisplayId = Display.DEFAULT_DISPLAY; // synchronized on sActiveDisplayLock
 
     private static Context sContext;
     private static Handler sHandler;
@@ -112,6 +120,18 @@
     }
 
     /**
+     * Query current display active id and publish the change if any.
+     */
+    static void updateActiveDisplayId(int displayId) {
+        synchronized (sActiveDisplayLock) {
+            if (displayId != Display.DEFAULT_DISPLAY && sDisplayId != displayId) {
+                sDisplayId = displayId;
+                AudioSystem.setParameters("active_displayId=" + sDisplayId);
+            }
+        }
+    }
+
+    /**
      * Uses android.hardware.display.DisplayManager.DisplayListener
      */
     final static class AudioDisplayListener implements DisplayManager.DisplayListener {
@@ -126,6 +146,7 @@
 
         @Override
         public void onDisplayChanged(int displayId) {
+            updateActiveDisplayId(displayId);
             updateOrientation();
         }
     }
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
new file mode 100644
index 0000000..708d9e1
--- /dev/null
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -0,0 +1,128 @@
+/*
+ * 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.audio;
+
+import android.annotation.NonNull;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioFormat;
+import android.media.ISpatializerCallback;
+import android.media.Spatializer;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class to manage Spatializer related functionality
+ */
+public class SpatializerHelper {
+
+    private static final String TAG = "AS.SpatializerHelper";
+
+    //---------------------------------------------------------------
+    // audio device compatibility / enabled
+
+    private final ArrayList<AudioDeviceAttributes> mCompatibleAudioDevices = new ArrayList<>(0);
+
+    /**
+     * @return a shallow copy of the list of compatible audio devices
+     */
+    synchronized @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
+        return (List<AudioDeviceAttributes>) mCompatibleAudioDevices.clone();
+    }
+
+    synchronized void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+        if (!mCompatibleAudioDevices.contains(ada)) {
+            mCompatibleAudioDevices.add(ada);
+        }
+    }
+
+    synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+        mCompatibleAudioDevices.remove(ada);
+    }
+
+    //------------------------------------------------------
+    // enabled state
+
+    // global state of feature
+    boolean mFeatureEnabled = false;
+    // initialized state, checked after each audio_server start
+    boolean mInitialized = false;
+
+    synchronized boolean isEnabled() {
+        return mFeatureEnabled;
+    }
+
+    synchronized boolean isAvailable() {
+        if (!mInitialized) {
+            return false;
+        }
+        // TODO check device compatibility
+        // ...
+        return true;
+    }
+
+    synchronized void setEnabled(boolean enabled) {
+        final boolean oldState = mFeatureEnabled;
+        mFeatureEnabled = enabled;
+        if (oldState != enabled) {
+            dispatchEnabledState();
+        }
+    }
+
+    public int getImmersiveAudioLevel() {
+        // TODO replace placeholder code with actual effect discovery
+        return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+    }
+
+    final RemoteCallbackList<ISpatializerCallback> mStateCallbacks =
+            new RemoteCallbackList<ISpatializerCallback>();
+
+    synchronized void registerStateCallback(
+            @NonNull ISpatializerCallback callback) {
+        mStateCallbacks.register(callback);
+    }
+
+    synchronized void unregisterStateCallback(
+            @NonNull ISpatializerCallback callback) {
+        mStateCallbacks.unregister(callback);
+    }
+
+    private synchronized void dispatchEnabledState() {
+        final int nbCallbacks = mStateCallbacks.beginBroadcast();
+        for (int i = 0; i < nbCallbacks; i++) {
+            try {
+                mStateCallbacks.getBroadcastItem(i)
+                        .dispatchSpatializerEnabledChanged(mFeatureEnabled);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in dispatchSpatializerEnabledChanged", e);
+            }
+        }
+        mStateCallbacks.finishBroadcast();
+    }
+
+    //------------------------------------------------------
+    // virtualization capabilities
+    synchronized boolean canBeSpatialized(
+            @NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
+        // TODO hook up to spatializer effect for query
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0cd2e3d..b42f898 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -206,7 +206,7 @@
         }
 
         @Override
-        public void authenticate(IBinder token, long sessionId, int userId,
+        public long authenticate(IBinder token, long sessionId, int userId,
                 IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo)
                 throws RemoteException {
             // Only allow internal clients to authenticate with a different userId.
@@ -223,18 +223,18 @@
 
             if (!checkAppOps(callingUid, opPackageName, "authenticate()")) {
                 authenticateFastFail("Denied by app ops: " + opPackageName, receiver);
-                return;
+                return -1;
             }
 
             if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
                 authenticateFastFail(
                         "Unable to authenticate, one or more null arguments", receiver);
-                return;
+                return -1;
             }
 
             if (!Utils.isForeground(callingUid, callingPid)) {
                 authenticateFastFail("Caller is not foreground: " + opPackageName, receiver);
-                return;
+                return -1;
             }
 
             if (promptInfo.containsTestConfigurations()) {
@@ -251,7 +251,7 @@
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                mBiometricService.authenticate(
+                return mBiometricService.authenticate(
                         token, sessionId, userId, receiver, opPackageName, promptInfo);
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -270,7 +270,7 @@
         }
 
         @Override
-        public void cancelAuthentication(IBinder token, String opPackageName)
+        public void cancelAuthentication(IBinder token, String opPackageName, long requestId)
                 throws RemoteException {
             checkPermission();
 
@@ -281,7 +281,7 @@
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                mBiometricService.cancelAuthentication(token, opPackageName);
+                mBiometricService.cancelAuthentication(token, opPackageName, requestId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index bdde980..0da6a1b 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -128,6 +128,7 @@
     @VisibleForTesting final IBinder mToken;
     // Info to be shown on BiometricDialog when all cookies are returned.
     @VisibleForTesting final PromptInfo mPromptInfo;
+    private final long mRequestId;
     private final long mOperationId;
     private final int mUserId;
     private final IBiometricSensorReceiver mSensorReceiver;
@@ -142,6 +143,8 @@
     private @BiometricMultiSensorMode int mMultiSensorMode;
     private @MultiSensorState int mMultiSensorState;
     private int[] mSensors;
+    // TODO(b/197265902): merge into state
+    private boolean mCancelled;
     // For explicit confirmation, do not send to keystore until the user has confirmed
     // the authentication.
     private byte[] mTokenEscrow;
@@ -162,6 +165,7 @@
             @NonNull ClientDeathReceiver clientDeathReceiver,
             @NonNull PreAuthInfo preAuthInfo,
             @NonNull IBinder token,
+            long requestId,
             long operationId,
             int userId,
             @NonNull IBiometricSensorReceiver sensorReceiver,
@@ -179,6 +183,7 @@
         mClientDeathReceiver = clientDeathReceiver;
         mPreAuthInfo = preAuthInfo;
         mToken = token;
+        mRequestId = requestId;
         mOperationId = operationId;
         mUserId = userId;
         mSensorReceiver = sensorReceiver;
@@ -187,6 +192,7 @@
         mPromptInfo = promptInfo;
         mDebugEnabled = debugEnabled;
         mFingerprintSensorProperties = fingerprintSensorProperties;
+        mCancelled = false;
 
         try {
             mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
@@ -233,7 +239,7 @@
                 Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id);
             }
             sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
-                    mUserId, mSensorReceiver, mOpPackageName, cookie,
+                    mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie,
                     mPromptInfo.isAllowBackgroundAuthentication());
         }
     }
@@ -255,8 +261,9 @@
                     true /* credentialAllowed */,
                     false /* requireConfirmation */,
                     mUserId,
-                    mOpPackageName,
                     mOperationId,
+                    mOpPackageName,
+                    mRequestId,
                     mMultiSensorMode);
         } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
             // Some combination of biometric or biometric|credential is requested
@@ -270,6 +277,11 @@
     }
 
     void onCookieReceived(int cookie) {
+        if (mCancelled) {
+            Slog.w(TAG, "Received cookie but already cancelled (ignoring): " + cookie);
+            return;
+        }
+
         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
             sensor.goToStateCookieReturnedIfCookieMatches(cookie);
         }
@@ -301,8 +313,9 @@
                             mPreAuthInfo.shouldShowCredential(),
                             requireConfirmation,
                             mUserId,
-                            mOpPackageName,
                             mOperationId,
+                            mOpPackageName,
+                            mRequestId,
                             mMultiSensorMode);
                     mState = STATE_AUTH_STARTED;
                 } catch (RemoteException e) {
@@ -369,7 +382,7 @@
                 final boolean shouldCancel = filter.apply(sensor);
                 Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel);
                 if (shouldCancel) {
-                    sensor.goToStateCancelling(mToken, mOpPackageName);
+                    sensor.goToStateCancelling(mToken, mOpPackageName, mRequestId);
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Unable to cancel authentication");
@@ -425,8 +438,9 @@
                             true /* credentialAllowed */,
                             false /* requireConfirmation */,
                             mUserId,
-                            mOpPackageName,
                             mOperationId,
+                            mOpPackageName,
+                            mRequestId,
                             mMultiSensorMode);
                 } else {
                     mClientReceiver.onError(modality, error, vendorCode);
@@ -775,6 +789,8 @@
      * @return true if this AuthSession is finished, e.g. should be set to null
      */
     boolean onCancelAuthSession(boolean force) {
+        mCancelled = true;
+
         final boolean authStarted = mState == STATE_AUTH_CALLED
                 || mState == STATE_AUTH_STARTED
                 || mState == STATE_AUTH_STARTED_UI_SHOWING;
@@ -820,6 +836,7 @@
         return Utils.isCredentialRequested(mPromptInfo);
     }
 
+    @VisibleForTesting
     boolean allCookiesReceived() {
         final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie();
         Slog.d(TAG, "Remaining cookies: " + remainingCookies);
@@ -839,6 +856,10 @@
         return mState;
     }
 
+    long getRequestId() {
+        return mRequestId;
+    }
+
     private int statsModality() {
         int modality = 0;
 
@@ -901,7 +922,9 @@
     @Override
     public String toString() {
         return "State: " + mState
+                + ", cancelled: " + mCancelled
                 + ", isCrypto: " + isCrypto()
-                + ", PreAuthInfo: " + mPreAuthInfo;
+                + ", PreAuthInfo: " + mPreAuthInfo
+                + ", requestId: " + mRequestId;
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 8a842b5..0333c3e 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -108,11 +108,11 @@
 
     void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie, boolean allowBackgroundAuthentication)
+            long requestId, int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
         mCookie = cookie;
         impl.prepareForAuthentication(requireConfirmation, token,
-                sessionId, userId, sensorReceiver, opPackageName, mCookie,
+                sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie,
                 allowBackgroundAuthentication);
         mSensorState = STATE_WAITING_FOR_COOKIE;
     }
@@ -129,8 +129,9 @@
         mSensorState = STATE_AUTHENTICATING;
     }
 
-    void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException {
-        impl.cancelAuthenticationFromService(token, opPackageName);
+    void goToStateCancelling(IBinder token, String opPackageName, long requestId)
+            throws RemoteException {
+        impl.cancelAuthenticationFromService(token, opPackageName, requestId);
         mSensorState = STATE_CANCELING;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index b1d300c..e0775d4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -83,6 +83,7 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * System service that arbitrates the modality for BiometricPrompt to use.
@@ -115,6 +116,7 @@
     final SettingObserver mSettingObserver;
     private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
     private final Random mRandom = new Random();
+    @NonNull private final AtomicLong mRequestCounter;
 
     @VisibleForTesting
     IStatusBarService mStatusBarService;
@@ -194,6 +196,7 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     handleAuthenticate(
                             (IBinder) args.arg1 /* token */,
+                            (long) args.arg6 /* requestId */,
                             (long) args.arg2 /* operationId */,
                             args.argi1 /* userid */,
                             (IBiometricServiceReceiver) args.arg3 /* receiver */,
@@ -204,7 +207,9 @@
                 }
 
                 case MSG_CANCEL_AUTHENTICATION: {
-                    handleCancelAuthentication();
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleCancelAuthentication((long) args.arg3 /* requestId */);
+                    args.recycle();
                     break;
                 }
 
@@ -683,13 +688,13 @@
         }
 
         @Override // Binder call
-        public void authenticate(IBinder token, long operationId, int userId,
+        public long authenticate(IBinder token, long operationId, int userId,
                 IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
             checkInternalPermission();
 
             if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
                 Slog.e(TAG, "Unable to authenticate, one or more null arguments");
-                return;
+                return -1;
             }
 
             if (!Utils.isValidAuthenticatorConfig(promptInfo)) {
@@ -706,6 +711,8 @@
                 }
             }
 
+            final long requestId = mRequestCounter.incrementAndGet();
+
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = token;
             args.arg2 = operationId;
@@ -713,15 +720,23 @@
             args.arg3 = receiver;
             args.arg4 = opPackageName;
             args.arg5 = promptInfo;
+            args.arg6 = requestId;
 
             mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
+
+            return requestId;
         }
 
         @Override // Binder call
-        public void cancelAuthentication(IBinder token, String opPackageName) {
+        public void cancelAuthentication(IBinder token, String opPackageName, long requestId) {
             checkInternalPermission();
 
-            mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget();
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = token;
+            args.arg2 = opPackageName;
+            args.arg3 = requestId;
+
+            mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget();
         }
 
         @Override // Binder call
@@ -1111,6 +1126,10 @@
             return Settings.Secure.getInt(context.getContentResolver(),
                     CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
         }
+
+        public AtomicLong getRequestGenerator() {
+            return new AtomicLong(0);
+        }
     }
 
     /**
@@ -1136,6 +1155,7 @@
         mEnabledOnKeyguardCallbacks = new ArrayList<>();
         mSettingObserver = mInjector.getSettingObserver(context, mHandler,
                 mEnabledOnKeyguardCallbacks);
+        mRequestCounter = mInjector.getRequestGenerator();
 
         // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't
         //  need to depend on context. We can remove this code once the advanced logic is enabled
@@ -1349,7 +1369,7 @@
         mCurrentAuthSession.onCookieReceived(cookie);
     }
 
-    private void handleAuthenticate(IBinder token, long operationId, int userId,
+    private void handleAuthenticate(IBinder token, long requestId, long operationId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
         mHandler.post(() -> {
             try {
@@ -1360,7 +1380,8 @@
                 final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();
 
                 Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first
-                        + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo);
+                        + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo
+                        + " requestId: " + requestId);
 
                 if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
                     // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
@@ -1372,8 +1393,8 @@
                         promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL);
                     }
 
-                    authenticateInternal(token, operationId, userId, receiver, opPackageName,
-                            promptInfo, preAuthInfo);
+                    authenticateInternal(token, requestId, operationId, userId, receiver,
+                            opPackageName, promptInfo, preAuthInfo);
                 } else {
                     receiver.onError(preAuthStatus.first /* modality */,
                             preAuthStatus.second /* errorCode */,
@@ -1394,7 +1415,7 @@
      * Note that this path is NOT invoked when the BiometricPrompt "Try again" button is pressed.
      * In that case, see {@link #handleOnTryAgainPressed()}.
      */
-    private void authenticateInternal(IBinder token, long operationId, int userId,
+    private void authenticateInternal(IBinder token, long requestId, long operationId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo,
             PreAuthInfo preAuthInfo) {
         Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo);
@@ -1412,9 +1433,9 @@
 
         final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId);
         mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver,
-                mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId,
-                mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled,
-                mInjector.getFingerprintSensorProperties(getContext()));
+                mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, requestId,
+                operationId, userId, mBiometricSensorReceiver, receiver, opPackageName, promptInfo,
+                debugEnabled, mInjector.getFingerprintSensorProperties(getContext()));
         try {
             mCurrentAuthSession.goToInitialState();
         } catch (RemoteException e) {
@@ -1422,11 +1443,21 @@
         }
     }
 
-    private void handleCancelAuthentication() {
+    private void handleCancelAuthentication(long requestId) {
         if (mCurrentAuthSession == null) {
             Slog.e(TAG, "handleCancelAuthentication: AuthSession is null");
             return;
         }
+        if (mCurrentAuthSession.getRequestId() != requestId) {
+            // TODO: actually cancel the operation
+            // This can happen if the operation has been queued, but is cancelled before
+            // it reaches the head of the scheduler. Consider it a programming error for now
+            // and ignore it.
+            Slog.e(TAG, "handleCancelAuthentication: AuthSession mismatch current requestId: "
+                    + mCurrentAuthSession.getRequestId() + " cancel for: " + requestId
+                    + " (ignoring cancellation)");
+            return;
+        }
 
         final boolean finished = mCurrentAuthSession.onCancelAuthSession(false /* force */);
         if (finished) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index e5e1385..0a1c77b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -101,6 +101,7 @@
     private final int mSensorId; // sensorId as configured by the framework
 
     @Nullable private IBinder mToken;
+    private long mRequestId;
     @Nullable private ClientMonitorCallbackConverter mListener;
     // Currently only used for authentication client. The cookie generated by BiometricService
     // is never 0.
@@ -154,6 +155,7 @@
         mSequentialId = sCount++;
         mContext = context;
         mToken = token;
+        mRequestId = -1;
         mListener = listener;
         mTargetUserId = userId;
         mOwner = owner;
@@ -206,7 +208,6 @@
             }
             mToken = null;
         }
-        mListener = null;
     }
 
     @Override
@@ -259,6 +260,29 @@
         return mSensorId;
     }
 
+    /** Unique request id. */
+    public final long getRequestId() {
+        return mRequestId;
+    }
+
+    /** If a unique id has been set via {@link #setRequestId(long)} */
+    public final boolean hasRequestId() {
+        return mRequestId > 0;
+    }
+
+    /**
+     * A unique identifier used to tie this operation to a request (i.e an API invocation).
+     *
+     * Subclasses should not call this method if this operation does not have a direct
+     * correspondence to a request and {@link #hasRequestId()} will return false.
+     */
+    protected final void setRequestId(long id) {
+        if (id <= 0) {
+            throw new IllegalArgumentException("request id must be positive");
+        }
+        mRequestId = id;
+    }
+
     @VisibleForTesting
     public Callback getCallback() {
         return mCallback;
@@ -271,6 +295,7 @@
                 + ", proto=" + getProtoEnum()
                 + ", owner=" + getOwnerString()
                 + ", cookie=" + getCookie()
+                + ", requestId=" + getRequestId()
                 + ", userId=" + getTargetUserId() + "}";
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index b20316e..361ec40 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -295,6 +295,7 @@
         @Override
         public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
             mHandler.post(() -> {
+                clientMonitor.destroy();
                 if (mCurrentOperation == null) {
                     Slog.e(getTag(), "[Finishing] " + clientMonitor
                             + " but current operation is null, success: " + success
@@ -642,22 +643,18 @@
     /**
      * Requests to cancel authentication or detection.
      * @param token from the caller, should match the token passed in when requesting authentication
+     * @param requestId the id returned when requesting authentication
      */
-    public void cancelAuthenticationOrDetection(IBinder token) {
-        if (mCurrentOperation == null) {
-            Slog.e(getTag(), "Unable to cancel authentication, null operation");
-            return;
-        }
-        final boolean isCorrectClient = isAuthenticationOrDetectionOperation(mCurrentOperation);
-        final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token;
+    public void cancelAuthenticationOrDetection(IBinder token, long requestId) {
+        Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId
+                + " current: " + mCurrentOperation
+                + " stack size: " + mPendingOperations.size());
 
-        Slog.d(getTag(), "cancelAuthenticationOrDetection, isCorrectClient: " + isCorrectClient
-                + ", tokenMatches: " + tokenMatches);
-
-        if (isCorrectClient && tokenMatches) {
+        if (mCurrentOperation != null
+                && canCancelAuthOperation(mCurrentOperation, token, requestId)) {
             Slog.d(getTag(), "Cancelling: " + mCurrentOperation);
             cancelInternal(mCurrentOperation);
-        } else if (!isCorrectClient) {
+        } else {
             // Look through the current queue for all authentication clients for the specified
             // token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking
             // all of them, instead of just the first one, since the API surface currently doesn't
@@ -665,8 +662,7 @@
             // process. However, this generally does not happen anyway, and would be a class of
             // bugs on its own.
             for (Operation operation : mPendingOperations) {
-                if (isAuthenticationOrDetectionOperation(operation)
-                        && operation.mClientMonitor.getToken() == token) {
+                if (canCancelAuthOperation(operation, token, requestId)) {
                     Slog.d(getTag(), "Marking " + operation
                             + " as STATE_WAITING_IN_QUEUE_CANCELING");
                     operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING;
@@ -675,10 +671,26 @@
         }
     }
 
-    private boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) {
-        final boolean isAuthentication = operation.mClientMonitor
-                instanceof AuthenticationConsumer;
-        final boolean isDetection = operation.mClientMonitor instanceof DetectionConsumer;
+    private static boolean canCancelAuthOperation(Operation operation, IBinder token,
+            long requestId) {
+        // TODO: restrict callers that can cancel without requestId (negative value)?
+        return isAuthenticationOrDetectionOperation(operation)
+                && operation.mClientMonitor.getToken() == token
+                && isMatchingRequestId(operation, requestId);
+    }
+
+    // By default, monitors are not associated with a request id to retain the original
+    // behavior (i.e. if no requestId is explicitly set then assume it matches)
+    private static boolean isMatchingRequestId(Operation operation, long requestId) {
+        return !operation.mClientMonitor.hasRequestId()
+                || operation.mClientMonitor.getRequestId() == requestId;
+    }
+
+    private static boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) {
+        final boolean isAuthentication =
+                operation.mClientMonitor instanceof AuthenticationConsumer;
+        final boolean isDetection =
+                operation.mClientMonitor instanceof DetectionConsumer;
         return isAuthentication || isDetection;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 0bc4f1b..b2fd46d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -61,10 +61,11 @@
     @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+            String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
         mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
-                userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);
+                userId, sensorReceiver, opPackageName, requestId, cookie,
+                allowBackgroundAuthentication);
     }
 
     @Override
@@ -73,9 +74,9 @@
     }
 
     @Override
-    public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+    public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
             throws RemoteException {
-        mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName);
+        mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, requestId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 12d6b08..675ee545 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -250,7 +250,7 @@
         }
 
         @Override // Binder call
-        public void authenticate(final IBinder token, final long operationId, int userId,
+        public long authenticate(final IBinder token, final long operationId, int userId,
                 final IFaceServiceReceiver receiver, final String opPackageName,
                 boolean isKeyguardBypassEnabled) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
@@ -270,38 +270,38 @@
             final Pair<Integer, ServiceProvider> provider = getSingleProvider();
             if (provider == null) {
                 Slog.w(TAG, "Null provider for authenticate");
-                return;
+                return -1;
             }
 
-            provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+            return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
                     0 /* cookie */,
                     new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
                     statsClient, isKeyguard, isKeyguardBypassEnabled);
         }
 
         @Override // Binder call
-        public void detectFace(final IBinder token, final int userId,
+        public long detectFace(final IBinder token, final int userId,
                 final IFaceServiceReceiver receiver, final String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
             if (!Utils.isKeyguard(getContext(), opPackageName)) {
                 Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName);
-                return;
+                return -1;
             }
 
             if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
                 // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
                 // ever be invoked when the user is encrypted or lockdown.
                 Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown");
-                return;
+                return -1;
             }
 
             final Pair<Integer, ServiceProvider> provider = getSingleProvider();
             if (provider == null) {
                 Slog.w(TAG, "Null provider for detectFace");
-                return;
+                return -1;
             }
 
-            provider.second.scheduleFaceDetect(provider.first, token, userId,
+            return provider.second.scheduleFaceDetect(provider.first, token, userId,
                     new ClientMonitorCallbackConverter(receiver), opPackageName,
                     BiometricsProtoEnums.CLIENT_KEYGUARD);
         }
@@ -309,8 +309,8 @@
         @Override // Binder call
         public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
                 IBinder token, long operationId, int userId,
-                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
-                boolean allowBackgroundAuthentication) {
+                IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
+                int cookie, boolean allowBackgroundAuthentication) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -322,9 +322,9 @@
             final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
             final boolean restricted = true; // BiometricPrompt is always restricted
             provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
-                    new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
-                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
-                    isKeyguardBypassEnabled);
+                    new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
+                    restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+                    allowBackgroundAuthentication, isKeyguardBypassEnabled);
         }
 
         @Override // Binder call
@@ -341,7 +341,8 @@
         }
 
         @Override // Binder call
-        public void cancelAuthentication(final IBinder token, final String opPackageName) {
+        public void cancelAuthentication(final IBinder token, final String opPackageName,
+                final long requestId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -350,11 +351,12 @@
                 return;
             }
 
-            provider.second.cancelAuthentication(provider.first, token);
+            provider.second.cancelAuthentication(provider.first, token, requestId);
         }
 
         @Override // Binder call
-        public void cancelFaceDetect(final IBinder token, final String opPackageName) {
+        public void cancelFaceDetect(final IBinder token, final String opPackageName,
+                final long requestId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
             if (!Utils.isKeyguard(getContext(), opPackageName)) {
                 Slog.w(TAG, "cancelFaceDetect called from non-sysui package: "
@@ -368,12 +370,12 @@
                 return;
             }
 
-            provider.second.cancelFaceDetect(provider.first, token);
+            provider.second.cancelFaceDetect(provider.first, token, requestId);
         }
 
         @Override // Binder call
         public void cancelAuthenticationFromService(int sensorId, final IBinder token,
-                final String opPackageName) {
+                final String opPackageName, final long requestId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -382,7 +384,7 @@
                 return;
             }
 
-            provider.cancelAuthentication(sensorId, token);
+            provider.cancelAuthentication(sensorId, token, requestId);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 93ab1b6..e099ba3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -101,18 +101,23 @@
 
     void cancelEnrollment(int sensorId, @NonNull IBinder token);
 
-    void scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId,
+    long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId,
             @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
             int statsClient);
 
-    void cancelFaceDetect(int sensorId, @NonNull IBinder token);
+    void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId);
 
-    void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+    long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
             int cookie, @NonNull ClientMonitorCallbackConverter callback,
             @NonNull String opPackageName, boolean restricted, int statsClient,
             boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
 
-    void cancelAuthentication(int sensorId, @NonNull IBinder token);
+    void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+            int cookie, @NonNull ClientMonitorCallbackConverter callback,
+            @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
+
+    void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);
 
     void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
             @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName);
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 d66a279..cbceba6 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
@@ -65,7 +65,8 @@
     @FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN;
 
     FaceAuthenticationClient(@NonNull Context context,
-            @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+            @NonNull LazyDaemon<ISession> lazyDaemon,
+            @NonNull IBinder token, long requestId,
             @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
             boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
             boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
@@ -76,6 +77,7 @@
                 BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
                 lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
                 isKeyguardBypassEnabled);
+        setRequestId(requestId);
         mUsageStats = usageStats;
         mLockoutCache = lockoutCache;
         mNotificationManager = context.getSystemService(NotificationManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index 1e73ac5..2ef0911 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -43,11 +43,13 @@
     @Nullable private ICancellationSignal mCancellationSignal;
 
     public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
-            @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+            @NonNull IBinder token, long requestId,
+            @NonNull ClientMonitorCallbackConverter listener, int userId,
             @NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
                 true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE,
                 BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+        setRequestId(requestId);
         mIsStrongBiometric = isStrongBiometric;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 718b9da..4bae775 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -65,6 +65,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Provider for a single instance of the {@link IFace} HAL.
@@ -83,6 +84,8 @@
     @NonNull private final UsageStats mUsageStats;
     @NonNull private final ActivityTaskManager mActivityTaskManager;
     @NonNull private final BiometricTaskStackListener mTaskStackListener;
+    // for requests that do not use biometric prompt
+    @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
 
     @Nullable private IFace mDaemon;
 
@@ -110,8 +113,8 @@
                                 && !client.isAlreadyDone()) {
                             Slog.e(getTag(), "Stopping background authentication, top: "
                                     + topPackage + " currentClient: " + client);
-                            mSensors.valueAt(i).getScheduler()
-                                    .cancelAuthenticationOrDetection(client.getToken());
+                            mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+                                    client.getToken(), client.getRequestId());
                         }
                     }
                 }
@@ -356,34 +359,39 @@
     }
 
     @Override
-    public void scheduleFaceDetect(int sensorId, @NonNull IBinder token,
+    public long scheduleFaceDetect(int sensorId, @NonNull IBinder token,
             int userId, @NonNull ClientMonitorCallbackConverter callback,
             @NonNull String opPackageName, int statsClient) {
+        final long id = mRequestCounter.incrementAndGet();
+
         mHandler.post(() -> {
             final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
             final FaceDetectClient client = new FaceDetectClient(mContext,
-                    mSensors.get(sensorId).getLazySession(), token, callback, userId, opPackageName,
+                    mSensors.get(sensorId).getLazySession(),
+                    token, id, callback, userId, opPackageName,
                     sensorId, isStrongBiometric, statsClient);
             scheduleForSensor(sensorId, client);
         });
+
+        return id;
     }
 
     @Override
-    public void cancelFaceDetect(int sensorId, @NonNull IBinder token) {
+    public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
         mHandler.post(() -> mSensors.get(sensorId).getScheduler()
-                .cancelAuthenticationOrDetection(token));
+                .cancelAuthenticationOrDetection(token, requestId));
     }
 
     @Override
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
-            @NonNull String opPackageName, boolean restricted, int statsClient,
+            @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
             boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
         mHandler.post(() -> {
             final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
             final FaceAuthenticationClient client = new FaceAuthenticationClient(
-                    mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
-                    operationId, restricted, opPackageName, cookie,
+                    mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
+                    userId, operationId, restricted, opPackageName, cookie,
                     false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
                     mUsageStats, mSensors.get(sensorId).getLockoutCache(),
                     allowBackgroundAuthentication, isKeyguardBypassEnabled);
@@ -392,9 +400,23 @@
     }
 
     @Override
-    public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+    public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+            int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
+        final long id = mRequestCounter.incrementAndGet();
+
+        scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
+                opPackageName, id, restricted, statsClient,
+                allowBackgroundAuthentication, isKeyguardBypassEnabled);
+
+        return id;
+    }
+
+    @Override
+    public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
         mHandler.post(() -> mSensors.get(sensorId).getScheduler()
-                .cancelAuthenticationOrDetection(token));
+                .cancelAuthenticationOrDetection(token, requestId));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index d05333d..f4dcbbb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -87,6 +87,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended
@@ -115,6 +116,8 @@
     @NonNull private final Map<Integer, Long> mAuthenticatorIds;
     @Nullable private IBiometricsFace mDaemon;
     @NonNull private final HalResultController mHalResultController;
+    // for requests that do not use biometric prompt
+    @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
     private int mCurrentUserId = UserHandle.USER_NULL;
     private final int mSensorId;
     private final List<Long> mGeneratedChallengeCount = new ArrayList<>();
@@ -605,7 +608,7 @@
     }
 
     @Override
-    public void scheduleFaceDetect(int sensorId, @NonNull IBinder token,
+    public long scheduleFaceDetect(int sensorId, @NonNull IBinder token,
             int userId, @NonNull ClientMonitorCallbackConverter callback,
             @NonNull String opPackageName, int statsClient) {
         throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you"
@@ -613,7 +616,7 @@
     }
 
     @Override
-    public void cancelFaceDetect(int sensorId, @NonNull IBinder token) {
+    public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
         throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you"
                 + "forget to check the supportsFaceDetection flag?");
     }
@@ -621,26 +624,38 @@
     @Override
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
-            @NonNull String opPackageName, boolean restricted, int statsClient,
+            @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
             boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
             final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId);
             final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
-                    mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
-                    cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
-                    statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication,
-                    isKeyguardBypassEnabled);
+                    mLazyDaemon, token, requestId, receiver, userId, operationId, restricted,
+                    opPackageName, cookie, false /* requireConfirmation */, mSensorId,
+                    isStrongBiometric, statsClient, mLockoutTracker, mUsageStats,
+                    allowBackgroundAuthentication, isKeyguardBypassEnabled);
             mScheduler.scheduleClientMonitor(client);
         });
     }
 
     @Override
-    public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
-        mHandler.post(() -> {
-            mScheduler.cancelAuthenticationOrDetection(token);
-        });
+    public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+            int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
+        final long id = mRequestCounter.incrementAndGet();
+
+        scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver,
+                opPackageName, id, restricted, statsClient,
+                allowBackgroundAuthentication, isKeyguardBypassEnabled);
+
+        return id;
+    }
+
+    @Override
+    public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
+        mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId));
     }
 
     @Override
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 33950af..40f2801 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
@@ -57,7 +57,8 @@
     private int mLastAcquire;
 
     FaceAuthenticationClient(@NonNull Context context,
-            @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
+            @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
+            @NonNull IBinder token, long requestId,
             @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
             boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
             boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
@@ -68,6 +69,7 @@
                 BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
                 lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
                 isKeyguardBypassEnabled);
+        setRequestId(requestId);
         mUsageStats = usageStats;
 
         final Resources resources = getContext().getResources();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 1e59429..52d887a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -61,10 +61,10 @@
     @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+            String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
         mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
-                sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);
+                sensorReceiver, opPackageName, requestId, cookie, allowBackgroundAuthentication);
     }
 
     @Override
@@ -73,9 +73,10 @@
     }
 
     @Override
-    public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+    public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
             throws RemoteException {
-        mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName);
+        mFingerprintService.cancelAuthenticationFromService(
+                mSensorId, token, opPackageName, requestId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 85817be..fa02c51 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -245,7 +245,7 @@
 
         @SuppressWarnings("deprecation")
         @Override // Binder call
-        public void authenticate(final IBinder token, final long operationId,
+        public long authenticate(final IBinder token, final long operationId,
                 final int sensorId, final int userId, final IFingerprintServiceReceiver receiver,
                 final String opPackageName) {
             final int callingUid = Binder.getCallingUid();
@@ -255,7 +255,7 @@
             if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid,
                     callingPid, callingUserId)) {
                 Slog.w(TAG, "Authenticate rejecting package: " + opPackageName);
-                return;
+                return -1;
             }
 
             // Keyguard check must be done on the caller's binder identity, since it also checks
@@ -270,7 +270,7 @@
                     // SafetyNet for b/79776455
                     EventLog.writeEvent(0x534e4554, "79776455");
                     Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown");
-                    return;
+                    return -1;
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity1);
@@ -290,7 +290,7 @@
             }
             if (provider == null) {
                 Slog.w(TAG, "Null provider for authenticate");
-                return;
+                return -1;
             }
 
             final FingerprintSensorPropertiesInternal sensorProps =
@@ -299,18 +299,17 @@
                     && sensorProps != null && sensorProps.isAnyUdfpsType()) {
                 final long identity2 = Binder.clearCallingIdentity();
                 try {
-                    authenticateWithPrompt(operationId, sensorProps, userId, receiver);
+                    return authenticateWithPrompt(operationId, sensorProps, userId, receiver);
                 } finally {
                     Binder.restoreCallingIdentity(identity2);
                 }
-            } else {
-                provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
-                        0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
-                        restricted, statsClient, isKeyguard, mFingerprintStateCallback);
             }
+            return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+                    0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
+                    restricted, statsClient, isKeyguard, mFingerprintStateCallback);
         }
 
-        private void authenticateWithPrompt(
+        private long authenticateWithPrompt(
                 final long operationId,
                 @NonNull final FingerprintSensorPropertiesInternal props,
                 final int userId,
@@ -387,33 +386,33 @@
                         }
                     };
 
-            biometricPrompt.authenticateUserForOperation(
+            return biometricPrompt.authenticateUserForOperation(
                     new CancellationSignal(), executor, promptCallback, userId, operationId);
         }
 
         @Override
-        public void detectFingerprint(final IBinder token, final int userId,
+        public long detectFingerprint(final IBinder token, final int userId,
                 final IFingerprintServiceReceiver receiver, final String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
             if (!Utils.isKeyguard(getContext(), opPackageName)) {
                 Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName);
-                return;
+                return -1;
             }
 
             if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
                 // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
                 // ever be invoked when the user is encrypted or lockdown.
                 Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
-                return;
+                return -1;
             }
 
             final Pair<Integer, ServiceProvider> provider = getSingleProvider();
             if (provider == null) {
                 Slog.w(TAG, "Null provider for detectFingerprint");
-                return;
+                return -1;
             }
 
-            provider.second.scheduleFingerDetect(provider.first, token, userId,
+            return provider.second.scheduleFingerDetect(provider.first, token, userId,
                     new ClientMonitorCallbackConverter(receiver), opPackageName,
                     BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback);
         }
@@ -421,7 +420,7 @@
         @Override // Binder call
         public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
                 int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-                int cookie, boolean allowBackgroundAuthentication) {
+                long requestId, int cookie, boolean allowBackgroundAuthentication) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -432,9 +431,9 @@
 
             final boolean restricted = true; // BiometricPrompt is always restricted
             provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
-                    new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
-                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
-                    mFingerprintStateCallback);
+                    new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
+                    restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+                    allowBackgroundAuthentication, mFingerprintStateCallback);
         }
 
         @Override // Binder call
@@ -452,7 +451,8 @@
 
 
         @Override // Binder call
-        public void cancelAuthentication(final IBinder token, final String opPackageName) {
+        public void cancelAuthentication(final IBinder token, final String opPackageName,
+                long requestId) {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
@@ -469,11 +469,12 @@
                 return;
             }
 
-            provider.second.cancelAuthentication(provider.first, token);
+            provider.second.cancelAuthentication(provider.first, token, requestId);
         }
 
         @Override // Binder call
-        public void cancelFingerprintDetect(final IBinder token, final String opPackageName) {
+        public void cancelFingerprintDetect(final IBinder token, final String opPackageName,
+                final long requestId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
             if (!Utils.isKeyguard(getContext(), opPackageName)) {
                 Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: "
@@ -489,12 +490,12 @@
                 return;
             }
 
-            provider.second.cancelAuthentication(provider.first, token);
+            provider.second.cancelAuthentication(provider.first, token, requestId);
         }
 
         @Override // Binder call
         public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
-                final String opPackageName) {
+                final String opPackageName, final long requestId) {
 
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
 
@@ -506,7 +507,7 @@
                 return;
             }
 
-            provider.cancelAuthentication(sensorId, token);
+            provider.cancelAuthentication(sensorId, token, requestId);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 706ac10..b9fcd8e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -95,20 +95,26 @@
 
     void cancelEnrollment(int sensorId, @NonNull IBinder token);
 
-    void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+    long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
             @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
             int statsClient,
             @NonNull FingerprintStateCallback fingerprintStateCallback);
 
     void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
             int cookie, @NonNull ClientMonitorCallbackConverter callback,
+            @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication,
+            @NonNull FingerprintStateCallback fingerprintStateCallback);
+
+    long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+            int cookie, @NonNull ClientMonitorCallbackConverter callback,
             @NonNull String opPackageName, boolean restricted, int statsClient,
             boolean allowBackgroundAuthentication,
             @NonNull FingerprintStateCallback fingerprintStateCallback);
 
     void startPreparedClient(int sensorId, int cookie);
 
-    void cancelAuthentication(int sensorId, @NonNull IBinder token);
+    void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);
 
     void scheduleRemove(int sensorId, @NonNull IBinder token,
             @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
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 37ee76a..9d911e0 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
@@ -61,7 +61,8 @@
     private boolean mIsPointerDown;
 
     FingerprintAuthenticationClient(@NonNull Context context,
-            @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+            @NonNull LazyDaemon<ISession> lazyDaemon,
+            @NonNull IBinder token, long requestId,
             @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
             boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
             int sensorId, boolean isStrongBiometric, int statsClient,
@@ -74,6 +75,7 @@
                 BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
                 lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
                 false /* isKeyguardBypassEnabled */);
+        setRequestId(requestId);
         mLockoutCache = lockoutCache;
         mUdfpsOverlayController = udfpsOverlayController;
         mSensorProps = sensorProps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index c5dc449..da91cdd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -47,13 +47,15 @@
     @Nullable private ICancellationSignal mCancellationSignal;
 
     FingerprintDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
-            @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+            @NonNull IBinder token, long requestId,
+            @NonNull ClientMonitorCallbackConverter listener, int userId,
             @NonNull String owner, int sensorId,
             @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric,
             int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
                 true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
                 BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+        setRequestId(requestId);
         mIsStrongBiometric = isStrongBiometric;
         mUdfpsOverlayController = udfpsOverlayController;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 102b074..377feca 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -71,6 +71,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Provider for a single instance of the {@link IFingerprint} HAL.
@@ -88,6 +89,8 @@
     @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
     @NonNull private final ActivityTaskManager mActivityTaskManager;
     @NonNull private final BiometricTaskStackListener mTaskStackListener;
+    // for requests that do not use biometric prompt
+    @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
 
     @Nullable private IFingerprint mDaemon;
     @Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@@ -118,8 +121,8 @@
                                 && !client.isAlreadyDone()) {
                             Slog.e(getTag(), "Stopping background authentication, top: "
                                     + topPackage + " currentClient: " + client);
-                            mSensors.valueAt(i).getScheduler()
-                                    .cancelAuthenticationOrDetection(client.getToken());
+                            mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+                                    client.getToken(), client.getRequestId());
                         }
                     }
                 }
@@ -369,31 +372,35 @@
     }
 
     @Override
-    public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+    public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
             @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
             int statsClient,
             @NonNull FingerprintStateCallback fingerprintStateCallback) {
+        final long id = mRequestCounter.incrementAndGet();
+
         mHandler.post(() -> {
             final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
             final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
-                    mSensors.get(sensorId).getLazySession(), token, callback, userId,
+                    mSensors.get(sensorId).getLazySession(), token, id, callback, userId,
                     opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric,
                     statsClient);
             scheduleForSensor(sensorId, client, fingerprintStateCallback);
         });
+
+        return id;
     }
 
     @Override
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
-            @NonNull String opPackageName, boolean restricted, int statsClient,
+            @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
             boolean allowBackgroundAuthentication,
             @NonNull FingerprintStateCallback fingerprintStateCallback) {
         mHandler.post(() -> {
             final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
             final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
-                    mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
-                    operationId, restricted, opPackageName, cookie,
+                    mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
+                    userId, operationId, restricted, opPackageName, cookie,
                     false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
                     mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
                     mUdfpsOverlayController, allowBackgroundAuthentication,
@@ -403,14 +410,29 @@
     }
 
     @Override
+    public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+            int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication,
+            @NonNull FingerprintStateCallback fingerprintStateCallback) {
+        final long id = mRequestCounter.incrementAndGet();
+
+        scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
+                opPackageName, id, restricted, statsClient, allowBackgroundAuthentication,
+                fingerprintStateCallback);
+
+        return id;
+    }
+
+    @Override
     public void startPreparedClient(int sensorId, int cookie) {
         mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie));
     }
 
     @Override
-    public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+    public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
         mHandler.post(() -> mSensors.get(sensorId).getScheduler()
-                .cancelAuthenticationOrDetection(token));
+                .cancelAuthenticationOrDetection(token, requestId));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 2f5b5c7..f17bcc8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -88,6 +88,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or
@@ -115,6 +116,8 @@
     @NonNull private final HalResultController mHalResultController;
     @Nullable private IUdfpsOverlayController mUdfpsOverlayController;
     @Nullable private ISidefpsController mSidefpsController;
+    // for requests that do not use biometric prompt
+    @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
     private int mCurrentUserId = UserHandle.USER_NULL;
     private final boolean mIsUdfps;
     private final int mSensorId;
@@ -142,7 +145,8 @@
                             && !client.isAlreadyDone()) {
                         Slog.e(TAG, "Stopping background authentication, top: "
                                 + topPackage + " currentClient: " + client);
-                        mScheduler.cancelAuthenticationOrDetection(client.getToken());
+                        mScheduler.cancelAuthenticationOrDetection(
+                                client.getToken(), client.getRequestId());
                     }
                 }
             });
@@ -591,26 +595,30 @@
     }
 
     @Override
-    public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+    public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
             @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
             int statsClient,
             @NonNull FingerprintStateCallback fingerprintStateCallback) {
+        final long id = mRequestCounter.incrementAndGet();
+
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
             final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
             final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
-                    mLazyDaemon, token, listener, userId, opPackageName,
+                    mLazyDaemon, token, id, listener, userId, opPackageName,
                     mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric,
                     statsClient);
             mScheduler.scheduleClientMonitor(client, fingerprintStateCallback);
         });
+
+        return id;
     }
 
     @Override
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
-            @NonNull String opPackageName, boolean restricted, int statsClient,
+            @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
             boolean allowBackgroundAuthentication,
             @NonNull FingerprintStateCallback fingerprintStateCallback) {
         mHandler.post(() -> {
@@ -618,8 +626,8 @@
 
             final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
             final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
-                    mContext, mLazyDaemon, token, listener, userId, operationId, restricted,
-                    opPackageName, cookie, false /* requireConfirmation */,
+                    mContext, mLazyDaemon, token, requestId, listener, userId, operationId,
+                    restricted, opPackageName, cookie, false /* requireConfirmation */,
                     mSensorProperties.sensorId, isStrongBiometric, statsClient,
                     mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
                     allowBackgroundAuthentication, mSensorProperties);
@@ -628,14 +636,29 @@
     }
 
     @Override
+    public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+            int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication,
+            @NonNull FingerprintStateCallback fingerprintStateCallback) {
+        final long id = mRequestCounter.incrementAndGet();
+
+        scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener,
+                opPackageName, id, restricted, statsClient, allowBackgroundAuthentication,
+                fingerprintStateCallback);
+
+        return id;
+    }
+
+    @Override
     public void startPreparedClient(int sensorId, int cookie) {
         mHandler.post(() -> mScheduler.startPreparedClient(cookie));
     }
 
     @Override
-    public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+    public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
         Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId);
-        mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token));
+        mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId));
     }
 
     @Override
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 5060744..7d95ec0 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
@@ -59,7 +59,8 @@
     private boolean mIsPointerDown;
 
     FingerprintAuthenticationClient(@NonNull Context context,
-            @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
+            @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon,
+            @NonNull IBinder token, long requestId,
             @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
             boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
             int sensorId, boolean isStrongBiometric, int statsClient,
@@ -73,6 +74,7 @@
                 BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
                 lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
                 false /* isKeyguardBypassEnabled */);
+        setRequestId(requestId);
         mLockoutFrameworkImpl = lockoutTracker;
         mUdfpsOverlayController = udfpsOverlayController;
         mSensorProps = sensorProps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 8e73ee6b..147a206 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -52,13 +52,15 @@
     private boolean mIsPointerDown;
 
     public FingerprintDetectClient(@NonNull Context context,
-            @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
+            @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon,
+            @NonNull IBinder token, long requestId,
             @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
             int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController,
             boolean isStrongBiometric, int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
                 true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
                 BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+        setRequestId(requestId);
         mUdfpsOverlayController = udfpsOverlayController;
         mIsStrongBiometric = isStrongBiometric;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 4918185..5c0c362 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -59,7 +59,7 @@
     @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long sessionId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+            String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
     }
 
@@ -68,7 +68,7 @@
     }
 
     @Override
-    public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+    public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
             throws RemoteException {
     }
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index f2e44ee..e7118ad 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -28,10 +28,8 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 
 class Tuner extends ITuner.Stub {
     private static final String TAG = "BroadcastRadioService.Tuner";
@@ -292,12 +290,12 @@
     }
 
     @Override
-    public Map setParameters(Map parameters) {
+    public Map<String, String> setParameters(Map<String, String> parameters) {
         throw new UnsupportedOperationException("Not supported by HAL 1.x");
     }
 
     @Override
-    public Map getParameters(List<String> keys) {
+    public Map<String, String> getParameters(List<String> keys) {
         throw new UnsupportedOperationException("Not supported by HAL 1.x");
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 7a6d964..867d5b4 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -18,12 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
 import android.hardware.radio.RadioTuner;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,7 +29,6 @@
 
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
@@ -176,7 +173,7 @@
     }
 
     @Override
-    public void onParametersUpdated(Map parameters) {
+    public void onParametersUpdated(Map<String, String> parameters) {
         Slog.e(TAG, "Not applicable for HAL 1.x");
     }
 
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 200af2f..d476fd6 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -301,7 +301,7 @@
     }
 
     @Override
-    public Map setParameters(Map parameters) {
+    public Map<String, String> setParameters(Map<String, String> parameters) {
         synchronized (mLock) {
             checkNotClosedLocked();
             return Convert.vendorInfoFromHal(Utils.maybeRethrow(
@@ -310,7 +310,7 @@
     }
 
     @Override
-    public Map getParameters(List<String> keys) {
+    public Map<String, String> getParameters(List<String> keys) {
         synchronized (mLock) {
             checkNotClosedLocked();
             return Convert.vendorInfoFromHal(Utils.maybeRethrow(
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 6610e8c..42b676f 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -692,8 +692,11 @@
             }
 
             try {
-                WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
-                        mDisplayWindowListener);
+                int[] displayIds = WindowManagerGlobal.getWindowManagerService()
+                        .registerDisplayWindowListener(mDisplayWindowListener);
+                for (int i = 0; i < displayIds.length; i++) {
+                    mDisplayWindowListener.onDisplayAdded(displayIds[i]);
+                }
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to register display window listener!");
             }
diff --git a/services/core/java/com/android/server/connectivity/PacProxyService.java b/services/core/java/com/android/server/connectivity/PacProxyService.java
index 0070339..3a97765 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyService.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyService.java
@@ -34,7 +34,6 @@
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteCallbackList;
@@ -42,6 +41,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -192,7 +192,7 @@
     }
 
     /**
-     * Updates the PAC Proxy Installer with current Proxy information. This is called by
+     * Updates the PAC Proxy Service with current Proxy information. This is called by
      * the ProxyTracker through PacProxyManager before a broadcast takes place to allow
      * the PacProxyService to indicate that the broadcast should not be sent and the
      * PacProxyService will trigger a new broadcast when it is ready.
@@ -357,8 +357,9 @@
                 }
             }
         };
-        mContext.bindService(intent, mConnection,
-                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE);
+        mContext.bindServiceAsUser(intent, mConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+                UserHandle.SYSTEM);
 
         intent = new Intent();
         intent.setClassName(PROXY_PACKAGE, PROXY_SERVICE);
@@ -398,9 +399,9 @@
                 }
             }
         };
-        mContext.bindService(intent,
+        mContext.bindServiceAsUser(intent, mProxyConnection,
                 Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
-                new HandlerExecutor(mNetThreadHandler), mProxyConnection);
+                mNetThreadHandler, UserHandle.SYSTEM);
     }
 
     private void unbind() {
diff --git a/services/core/java/com/android/server/devicestate/DeviceState.java b/services/core/java/com/android/server/devicestate/DeviceState.java
index e693bcc..7fe24ff 100644
--- a/services/core/java/com/android/server/devicestate/DeviceState.java
+++ b/services/core/java/com/android/server/devicestate/DeviceState.java
@@ -19,11 +19,14 @@
 import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
 
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -39,6 +42,19 @@
  * @see DeviceStateManagerService
  */
 public final class DeviceState {
+    /**
+     * Flag that indicates sticky requests should be cancelled when this device state becomes the
+     * base device state.
+     */
+    public static final int FLAG_CANCEL_STICKY_REQUESTS = 1 << 0;
+
+    /** @hide */
+    @IntDef(prefix = {"FLAG_"}, flag = true, value = {
+            FLAG_CANCEL_STICKY_REQUESTS,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DeviceStateFlags {}
+
     /** Unique identifier for the device state. */
     @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE)
     private final int mIdentifier;
@@ -47,14 +63,19 @@
     @NonNull
     private final String mName;
 
+    @DeviceStateFlags
+    private final int mFlags;
+
     public DeviceState(
             @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
-            @NonNull String name) {
+            @NonNull String name,
+            @DeviceStateFlags int flags) {
         Preconditions.checkArgumentInRange(identifier, MINIMUM_DEVICE_STATE, MAXIMUM_DEVICE_STATE,
                 "identifier");
 
         mIdentifier = identifier;
         mName = name;
+        mFlags = flags;
     }
 
     /** Returns the unique identifier for the device state. */
@@ -69,6 +90,11 @@
         return mName;
     }
 
+    @DeviceStateFlags
+    public int getFlags() {
+        return mFlags;
+    }
+
     @Override
     public String toString() {
         return "DeviceState{" + "identifier=" + mIdentifier + ", name='" + mName + '\'' + '}';
@@ -80,11 +106,12 @@
         if (o == null || getClass() != o.getClass()) return false;
         DeviceState that = (DeviceState) o;
         return mIdentifier == that.mIdentifier
-                && Objects.equals(mName, that.mName);
+                && Objects.equals(mName, that.mName)
+                && mFlags == that.mFlags;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mIdentifier, mName);
+        return Objects.hash(mIdentifier, mName, mFlags);
     }
 }
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index a8b0994..383b392 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -19,8 +19,13 @@
 import static android.Manifest.permission.CONTROL_DEVICE_STATE;
 import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES;
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
 
+import static com.android.server.devicestate.OverrideRequestController.STATUS_ACTIVE;
+import static com.android.server.devicestate.OverrideRequestController.STATUS_CANCELED;
+import static com.android.server.devicestate.OverrideRequestController.STATUS_SUSPENDED;
+
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,12 +35,12 @@
 import android.hardware.devicestate.IDeviceStateManager;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
-import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -43,14 +48,21 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.policy.DeviceStatePolicyImpl;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.WindowProcessController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Optional;
+import java.util.WeakHashMap;
 
 /**
  * A system service that manages the state of a device with user-configurable hardware like a
@@ -81,10 +93,20 @@
     private static final boolean DEBUG = false;
 
     private final Object mLock = new Object();
+    // Internal system service thread used to dispatch calls to the policy and to registered
+    // callbacks though its handler (mHandler). Provides a guarantee of callback order when
+    // leveraging mHandler and also enables posting messages with the service lock held.
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
     @NonNull
     private final DeviceStatePolicy mDeviceStatePolicy;
     @NonNull
     private final BinderService mBinderService;
+    @NonNull
+    private final OverrideRequestController mOverrideRequestController;
+    @VisibleForTesting
+    @NonNull
+    public ActivityTaskManagerInternal mActivityTaskManagerInternal;
 
     // All supported device states keyed by identifier.
     @GuardedBy("mLock")
@@ -109,17 +131,16 @@
     @NonNull
     private Optional<DeviceState> mBaseState = Optional.empty();
 
+    // The current active override request. When set the device state specified here will take
+    // precedence over mBaseState.
+    @GuardedBy("mLock")
+    @NonNull
+    private Optional<OverrideRequest> mActiveOverride = Optional.empty();
+
     // List of processes registered to receive notifications about changes to device state and
     // request status indexed by process id.
     @GuardedBy("mLock")
     private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>();
-    // List of override requests with the highest precedence request at the end.
-    @GuardedBy("mLock")
-    private final ArrayList<OverrideRequestRecord> mRequestRecords = new ArrayList<>();
-    // Set of override requests that are pending a call to notifyStatusIfNeeded() to be notified
-    // of a change in status.
-    @GuardedBy("mLock")
-    private final ArraySet<OverrideRequestRecord> mRequestsPendingStatusChange = new ArraySet<>();
 
     public DeviceStateManagerService(@NonNull Context context) {
         this(context, new DeviceStatePolicyImpl(context));
@@ -128,9 +149,17 @@
     @VisibleForTesting
     DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) {
         super(context);
+        // Service thread assigned THREAD_PRIORITY_DISPLAY because this service indirectly drives
+        // display (on/off) and window (position) events through its callbacks.
+        mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_DISPLAY, false /* allowIo */);
+        mHandlerThread.start();
+        mHandler = mHandlerThread.getThreadHandler();
+        mOverrideRequestController = new OverrideRequestController(
+                this::onOverrideRequestStatusChangedLocked);
         mDeviceStatePolicy = policy;
         mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
         mBinderService = new BinderService();
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
     }
 
     @Override
@@ -138,6 +167,11 @@
         publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
     }
 
+    @VisibleForTesting
+    Handler getHandler() {
+        return mHandler;
+    }
+
     /**
      * Returns the current state the system is in. Note that the system may be in the process of
      * configuring a different state.
@@ -191,12 +225,10 @@
     @NonNull
     Optional<DeviceState> getOverrideState() {
         synchronized (mLock) {
-            if (mRequestRecords.isEmpty()) {
-                return Optional.empty();
+            if (mActiveOverride.isPresent()) {
+                return getStateLocked(mActiveOverride.get().getRequestedState());
             }
-
-            OverrideRequestRecord topRequest = mRequestRecords.get(mRequestRecords.size() - 1);
-            return Optional.of(topRequest.mRequestedState);
+            return Optional.empty();
         }
     }
 
@@ -247,43 +279,41 @@
     }
 
     private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
-        boolean updatedPendingState;
-        boolean hasBaseState;
         synchronized (mLock) {
             final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
 
+            // Whether or not at least one device state has the flag FLAG_CANCEL_STICKY_REQUESTS
+            // set. If set to true, the OverrideRequestController will be configured to allow sticky
+            // requests.
+            boolean hasTerminalDeviceState = false;
             mDeviceStates.clear();
             for (int i = 0; i < supportedDeviceStates.length; i++) {
                 DeviceState state = supportedDeviceStates[i];
+                if ((state.getFlags() & DeviceState.FLAG_CANCEL_STICKY_REQUESTS) != 0) {
+                    hasTerminalDeviceState = true;
+                }
                 mDeviceStates.put(state.getIdentifier(), state);
             }
 
+            mOverrideRequestController.setStickyRequestsAllowed(hasTerminalDeviceState);
+
             final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked();
             if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) {
                 return;
             }
 
-            final int requestSize = mRequestRecords.size();
-            for (int i = 0; i < requestSize; i++) {
-                OverrideRequestRecord request = mRequestRecords.get(i);
-                if (!isSupportedStateLocked(request.mRequestedState.getIdentifier())) {
-                    request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED);
-                }
+            mOverrideRequestController.handleNewSupportedStates(newStateIdentifiers);
+            updatePendingStateLocked();
+
+            if (!mPendingState.isPresent()) {
+                // If the change in the supported states didn't result in a change of the pending
+                // state commitPendingState() will never be called and the callbacks will never be
+                // notified of the change.
+                notifyDeviceStateInfoChangedAsync();
             }
 
-            updatedPendingState = updatePendingStateLocked();
-            hasBaseState = mBaseState.isPresent();
+            mHandler.post(this::notifyPolicyIfNeeded);
         }
-
-        if (hasBaseState && !updatedPendingState) {
-            // If the change in the supported states didn't result in a change of the pending state
-            // commitPendingState() will never be called and the callbacks will never be notified
-            // of the change.
-            notifyDeviceStateInfoChanged();
-        }
-
-        notifyRequestsOfStatusChangeIfNeeded();
-        notifyPolicyIfNeeded();
     }
 
     /**
@@ -311,7 +341,6 @@
      * @see #isSupportedStateLocked(int)
      */
     private void setBaseState(int identifier) {
-        boolean updatedPendingState;
         synchronized (mLock) {
             final Optional<DeviceState> baseStateOptional = getStateLocked(identifier);
             if (!baseStateOptional.isPresent()) {
@@ -325,26 +354,21 @@
             }
             mBaseState = Optional.of(baseState);
 
-            final int requestSize = mRequestRecords.size();
-            for (int i = 0; i < requestSize; i++) {
-                OverrideRequestRecord request = mRequestRecords.get(i);
-                if ((request.mFlags & FLAG_CANCEL_WHEN_BASE_CHANGES) > 0) {
-                    request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED);
-                }
+            if ((baseState.getFlags() & DeviceState.FLAG_CANCEL_STICKY_REQUESTS) != 0) {
+                mOverrideRequestController.cancelStickyRequests();
+            }
+            mOverrideRequestController.handleBaseStateChanged();
+            updatePendingStateLocked();
+
+            if (!mPendingState.isPresent()) {
+                // If the change in base state didn't result in a change of the pending state
+                // commitPendingState() will never be called and the callbacks will never be
+                // notified of the change.
+                notifyDeviceStateInfoChangedAsync();
             }
 
-            updatedPendingState = updatePendingStateLocked();
+            mHandler.post(this::notifyPolicyIfNeeded);
         }
-
-        if (!updatedPendingState) {
-            // If the change in base state didn't result in a change of the pending state
-            // commitPendingState() will never be called and the callbacks will never be notified
-            // of the change.
-            notifyDeviceStateInfoChanged();
-        }
-
-        notifyRequestsOfStatusChangeIfNeeded();
-        notifyPolicyIfNeeded();
     }
 
     /**
@@ -362,8 +386,8 @@
         }
 
         final DeviceState stateToConfigure;
-        if (!mRequestRecords.isEmpty()) {
-            stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
+        if (mActiveOverride.isPresent()) {
+            stateToConfigure = getStateLocked(mActiveOverride.get().getRequestedState()).get();
         } else if (mBaseState.isPresent()
                 && isSupportedStateLocked(mBaseState.get().getIdentifier())) {
             // Base state could have recently become unsupported after a change in supported states.
@@ -429,108 +453,106 @@
      * </p>
      */
     private void commitPendingState() {
-        // Update the current state.
         synchronized (mLock) {
             final DeviceState newState = mPendingState.get();
             if (DEBUG) {
                 Slog.d(TAG, "Committing state: " + newState);
             }
 
-            if (!mRequestRecords.isEmpty()) {
-                final OverrideRequestRecord topRequest =
-                        mRequestRecords.get(mRequestRecords.size() - 1);
-                if (topRequest.mRequestedState.getIdentifier() == newState.getIdentifier()) {
-                    // The top request could have come in while the service was awaiting callback
-                    // from the policy. In that case we only set it to active if it matches the
-                    // current committed state, otherwise it will be set to active when its
-                    // requested state is committed.
-                    topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE);
-                }
-            }
-
             FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_STATE_CHANGED,
                     newState.getIdentifier(), !mCommittedState.isPresent());
 
             mCommittedState = Optional.of(newState);
             mPendingState = Optional.empty();
             updatePendingStateLocked();
+
+            // Notify callbacks of a change.
+            notifyDeviceStateInfoChangedAsync();
+
+            // The top request could have come in while the service was awaiting callback
+            // from the policy. In that case we only set it to active if it matches the
+            // current committed state, otherwise it will be set to active when its
+            // requested state is committed.
+            OverrideRequest activeRequest = mActiveOverride.orElse(null);
+            if (activeRequest != null
+                    && activeRequest.getRequestedState() == newState.getIdentifier()) {
+                ProcessRecord processRecord = mProcessRecords.get(activeRequest.getPid());
+                if (processRecord != null) {
+                    processRecord.notifyRequestActiveAsync(activeRequest.getToken());
+                }
+            }
+
+            // Try to configure the next state if needed.
+            mHandler.post(this::notifyPolicyIfNeeded);
         }
-
-        // Notify callbacks of a change.
-        notifyDeviceStateInfoChanged();
-
-        // Notify the top request that it's active.
-        notifyRequestsOfStatusChangeIfNeeded();
-
-        // Try to configure the next state if needed.
-        notifyPolicyIfNeeded();
     }
 
-    private void notifyDeviceStateInfoChanged() {
-        if (Thread.holdsLock(mLock)) {
-            throw new IllegalStateException(
-                    "Attempting to notify callbacks with service lock held.");
-        }
-
-        // Grab the lock and copy the process records and the current info.
-        ArrayList<ProcessRecord> registeredProcesses;
-        DeviceStateInfo info;
+    private void notifyDeviceStateInfoChangedAsync() {
         synchronized (mLock) {
             if (mProcessRecords.size() == 0) {
                 return;
             }
 
-            registeredProcesses = new ArrayList<>();
+            ArrayList<ProcessRecord> registeredProcesses = new ArrayList<>();
             for (int i = 0; i < mProcessRecords.size(); i++) {
                 registeredProcesses.add(mProcessRecords.valueAt(i));
             }
 
-            info = getDeviceStateInfoLocked();
-        }
+            DeviceStateInfo info = getDeviceStateInfoLocked();
 
-        // After releasing the lock, send the notifications out.
-        for (int i = 0; i < registeredProcesses.size(); i++) {
-            registeredProcesses.get(i).notifyDeviceStateInfoAsync(info);
+            for (int i = 0; i < registeredProcesses.size(); i++) {
+                registeredProcesses.get(i).notifyDeviceStateInfoAsync(info);
+            }
         }
     }
 
-    /**
-     * Notifies all dirty requests (requests that have a change in status, but have not yet been
-     * notified) that their status has changed.
-     */
-    private void notifyRequestsOfStatusChangeIfNeeded() {
-        if (Thread.holdsLock(mLock)) {
-            throw new IllegalStateException(
-                    "Attempting to notify requests with service lock held.");
-        }
-
-        ArraySet<OverrideRequestRecord> dirtyRequests;
-        synchronized (mLock) {
-            if (mRequestsPendingStatusChange.isEmpty()) {
-                return;
+    private void onOverrideRequestStatusChangedLocked(@NonNull OverrideRequest request,
+            @OverrideRequestController.RequestStatus int status) {
+        if (status == STATUS_ACTIVE) {
+            mActiveOverride = Optional.of(request);
+        } else if (status == STATUS_SUSPENDED || status == STATUS_CANCELED) {
+            if (mActiveOverride.isPresent() && mActiveOverride.get() == request) {
+                mActiveOverride = Optional.empty();
             }
-
-            dirtyRequests = new ArraySet<>(mRequestsPendingStatusChange);
-            mRequestsPendingStatusChange.clear();
+        } else {
+            throw new IllegalArgumentException("Unknown request status: " + status);
         }
 
-        // After releasing the lock, send the notifications out.
-        for (int i = 0; i < dirtyRequests.size(); i++) {
-            dirtyRequests.valueAt(i).notifyStatusIfNeeded();
+        boolean updatedPendingState = updatePendingStateLocked();
+
+        ProcessRecord processRecord = mProcessRecords.get(request.getPid());
+        if (processRecord == null) {
+            // If the process is no longer registered with the service, for example if it has died,
+            // there is no need to notify it of a change in request status.
+            mHandler.post(this::notifyPolicyIfNeeded);
+            return;
         }
+
+        if (status == STATUS_ACTIVE) {
+            if (!updatedPendingState && !mPendingState.isPresent()) {
+                // If the pending state was not updated and there is not currently a pending state
+                // then this newly active request will never be notified of a change in state.
+                // Schedule the notification now.
+                processRecord.notifyRequestActiveAsync(request.getToken());
+            }
+        } else if (status == STATUS_SUSPENDED) {
+            processRecord.notifyRequestSuspendedAsync(request.getToken());
+        } else {
+            processRecord.notifyRequestCanceledAsync(request.getToken());
+        }
+
+        mHandler.post(this::notifyPolicyIfNeeded);
     }
 
     private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
-        DeviceStateInfo currentInfo;
-        ProcessRecord record;
-        // Grab the lock to register the callback and get the current state.
         synchronized (mLock) {
             if (mProcessRecords.contains(pid)) {
                 throw new SecurityException("The calling process has already registered an"
                         + " IDeviceStateManagerCallback.");
             }
 
-            record = new ProcessRecord(callback, pid);
+            ProcessRecord record = new ProcessRecord(callback, pid, this::handleProcessDied,
+                    mHandlerThread.getThreadHandler());
             try {
                 callback.asBinder().linkToDeath(record, 0);
             } catch (RemoteException ex) {
@@ -538,34 +560,21 @@
             }
             mProcessRecords.put(pid, record);
 
-            currentInfo = mCommittedState.isPresent() ? getDeviceStateInfoLocked() : null;
-        }
-
-        if (currentInfo != null) {
-            // If there is not a committed state we'll wait to notify the process of the initial
-            // value.
-            record.notifyDeviceStateInfoAsync(currentInfo);
+            DeviceStateInfo currentInfo = mCommittedState.isPresent()
+                    ? getDeviceStateInfoLocked() : null;
+            if (currentInfo != null) {
+                // If there is not a committed state we'll wait to notify the process of the initial
+                // value.
+                record.notifyDeviceStateInfoAsync(currentInfo);
+            }
         }
     }
 
     private void handleProcessDied(ProcessRecord processRecord) {
         synchronized (mLock) {
-            // Cancel all requests from this process.
-            final int requestCount = processRecord.mRequestRecords.size();
-            for (int i = 0; i < requestCount; i++) {
-                final OverrideRequestRecord request = processRecord.mRequestRecords.valueAt(i);
-                // Cancel the request but don't mark it as dirty since there's no need to send
-                // notifications if the process has died.
-                request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED,
-                        false /* markDirty */);
-            }
-
             mProcessRecords.remove(processRecord.mPid);
-
-            updatePendingStateLocked();
+            mOverrideRequestController.handleProcessDied(processRecord.mPid);
         }
-
-        notifyPolicyIfNeeded();
     }
 
     private void requestStateInternal(int state, int flags, int callingPid,
@@ -577,7 +586,7 @@
                         + " has no registered callback.");
             }
 
-            if (processRecord.mRequestRecords.get(token) != null) {
+            if (mOverrideRequestController.hasRequest(token)) {
                 throw new IllegalStateException("Request has already been made for the supplied"
                         + " token: " + token);
             }
@@ -588,27 +597,9 @@
                         + " is not supported.");
             }
 
-            OverrideRequestRecord topRecord = mRequestRecords.isEmpty()
-                    ? null : mRequestRecords.get(mRequestRecords.size() - 1);
-            if (topRecord != null) {
-                topRecord.setStatusLocked(OverrideRequestRecord.STATUS_SUSPENDED);
-            }
-
-            final OverrideRequestRecord request =
-                    new OverrideRequestRecord(processRecord, token, deviceState.get(), flags);
-            mRequestRecords.add(request);
-            processRecord.mRequestRecords.put(request.mToken, request);
-
-            final boolean updatedPendingState = updatePendingStateLocked();
-            if (!updatedPendingState && !mPendingState.isPresent()) {
-                // We don't set the status of the new request to ACTIVE if the request updated the
-                // pending state as it will be set in commitPendingState().
-                request.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE, true /* markDirty */);
-            }
+            OverrideRequest request = new OverrideRequest(token, callingPid, state, flags);
+            mOverrideRequestController.addRequest(request);
         }
-
-        notifyRequestsOfStatusChangeIfNeeded();
-        notifyPolicyIfNeeded();
     }
 
     private void cancelRequestInternal(int callingPid, @NonNull IBinder token) {
@@ -619,18 +610,8 @@
                         + " has no registered callback.");
             }
 
-            OverrideRequestRecord request = processRecord.mRequestRecords.get(token);
-            if (request == null) {
-                throw new IllegalStateException("No known request for the given token");
-            }
-
-            request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED);
-
-            updatePendingStateLocked();
+            mOverrideRequestController.cancelRequest(token);
         }
-
-        notifyRequestsOfStatusChangeIfNeeded();
-        notifyPolicyIfNeeded();
     }
 
     private void dumpInternal(PrintWriter pw) {
@@ -650,16 +631,7 @@
                 pw.println("  " + i + ": mPid=" + processRecord.mPid);
             }
 
-            final int requestCount = mRequestRecords.size();
-            pw.println();
-            pw.println("Override requests: size=" + requestCount);
-            for (int i = 0; i < requestCount; i++) {
-                OverrideRequestRecord requestRecord = mRequestRecords.get(i);
-                pw.println("  " + i + ": mPid=" + requestRecord.mProcessRecord.mPid
-                        + ", mRequestedState=" + requestRecord.mRequestedState
-                        + ", mFlags=" + requestRecord.mFlags
-                        + ", mStatus=" + requestRecord.statusToString(requestRecord.mStatus));
-            }
+            mOverrideRequestController.dumpInternal(pw);
         }
     }
 
@@ -683,142 +655,107 @@
         }
     }
 
-    private final class ProcessRecord implements IBinder.DeathRecipient {
+    private static final class ProcessRecord implements IBinder.DeathRecipient {
+        public interface DeathListener {
+            void onProcessDied(ProcessRecord record);
+        }
+
+        private static final int STATUS_ACTIVE = 0;
+
+        private static final int STATUS_SUSPENDED = 1;
+
+        private static final int STATUS_CANCELED = 2;
+
+        @IntDef(prefix = {"STATUS_"}, value = {
+                STATUS_ACTIVE,
+                STATUS_SUSPENDED,
+                STATUS_CANCELED
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        private @interface RequestStatus {}
+
         private final IDeviceStateManagerCallback mCallback;
         private final int mPid;
+        private final DeathListener mDeathListener;
+        private final Handler mHandler;
 
-        private final ArrayMap<IBinder, OverrideRequestRecord> mRequestRecords = new ArrayMap<>();
+        private final WeakHashMap<IBinder, Integer> mLastNotifiedStatus = new WeakHashMap<>();
 
-        ProcessRecord(IDeviceStateManagerCallback callback, int pid) {
+        ProcessRecord(IDeviceStateManagerCallback callback, int pid, DeathListener deathListener,
+                Handler handler) {
             mCallback = callback;
             mPid = pid;
+            mDeathListener = deathListener;
+            mHandler = handler;
         }
 
         @Override
         public void binderDied() {
-            handleProcessDied(this);
+            mDeathListener.onProcessDied(this);
         }
 
         public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) {
-            try {
-                mCallback.onDeviceStateInfoChanged(info);
-            } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
-                        ex);
-            }
-        }
-
-        public void notifyRequestActiveAsync(OverrideRequestRecord request) {
-            try {
-                mCallback.onRequestActive(request.mToken);
-            } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
-                        ex);
-            }
-        }
-
-        public void notifyRequestSuspendedAsync(OverrideRequestRecord request) {
-            try {
-                mCallback.onRequestSuspended(request.mToken);
-            } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
-                        ex);
-            }
-        }
-
-        public void notifyRequestCanceledAsync(OverrideRequestRecord request) {
-            try {
-                mCallback.onRequestCanceled(request.mToken);
-            } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
-                        ex);
-            }
-        }
-    }
-
-    /** A record describing a request to override the state of the device. */
-    private final class OverrideRequestRecord {
-        public static final int STATUS_UNKNOWN = 0;
-        public static final int STATUS_ACTIVE = 1;
-        public static final int STATUS_SUSPENDED = 2;
-        public static final int STATUS_CANCELED = 3;
-
-        @Nullable
-        public String statusToString(int status) {
-            switch (status) {
-                case STATUS_ACTIVE:
-                    return "ACTIVE";
-                case STATUS_SUSPENDED:
-                    return "SUSPENDED";
-                case STATUS_CANCELED:
-                    return "CANCELED";
-                case STATUS_UNKNOWN:
-                    return "UNKNOWN";
-                default:
-                    return null;
-            }
-        }
-
-        private final ProcessRecord mProcessRecord;
-        @NonNull
-        private final IBinder mToken;
-        @NonNull
-        private final DeviceState mRequestedState;
-        private final int mFlags;
-
-        private int mStatus = STATUS_UNKNOWN;
-        private int mLastNotifiedStatus = STATUS_UNKNOWN;
-
-        OverrideRequestRecord(@NonNull ProcessRecord processRecord, @NonNull IBinder token,
-                @NonNull DeviceState requestedState, int flags) {
-            mProcessRecord = processRecord;
-            mToken = token;
-            mRequestedState = requestedState;
-            mFlags = flags;
-        }
-
-        public void setStatusLocked(int status) {
-            setStatusLocked(status, true /* markDirty */);
-        }
-
-        public void setStatusLocked(int status, boolean markDirty) {
-            if (mStatus != status) {
-                if (mStatus == STATUS_CANCELED) {
-                    throw new IllegalStateException(
-                            "Can not alter the status of a request after set to CANCELED.");
+            mHandler.post(() -> {
+                try {
+                    mCallback.onDeviceStateInfoChanged(info);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
+                            ex);
                 }
-
-                mStatus = status;
-
-                if (mStatus == STATUS_CANCELED) {
-                    mRequestRecords.remove(this);
-                    mProcessRecord.mRequestRecords.remove(mToken);
-                }
-
-                if (markDirty) {
-                    mRequestsPendingStatusChange.add(this);
-                }
-            }
+            });
         }
 
-        public void notifyStatusIfNeeded() {
-            int stateToReport;
-            synchronized (mLock) {
-                if (mLastNotifiedStatus == mStatus) {
-                    return;
+        public void notifyRequestActiveAsync(IBinder token) {
+            @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token);
+            if (lastStatus != null
+                    && (lastStatus == STATUS_ACTIVE || lastStatus == STATUS_CANCELED)) {
+                return;
+            }
+
+            mLastNotifiedStatus.put(token, STATUS_ACTIVE);
+            mHandler.post(() -> {
+                try {
+                    mCallback.onRequestActive(token);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
+                            ex);
                 }
+            });
+        }
 
-                stateToReport = mStatus;
-                mLastNotifiedStatus = mStatus;
+        public void notifyRequestSuspendedAsync(IBinder token) {
+            @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token);
+            if (lastStatus != null
+                    && (lastStatus == STATUS_SUSPENDED || lastStatus == STATUS_CANCELED)) {
+                return;
             }
 
-            if (stateToReport == STATUS_ACTIVE) {
-                mProcessRecord.notifyRequestActiveAsync(this);
-            } else if (stateToReport == STATUS_SUSPENDED) {
-                mProcessRecord.notifyRequestSuspendedAsync(this);
-            } else if (stateToReport == STATUS_CANCELED) {
-                mProcessRecord.notifyRequestCanceledAsync(this);
+            mLastNotifiedStatus.put(token, STATUS_SUSPENDED);
+            mHandler.post(() -> {
+                try {
+                    mCallback.onRequestSuspended(token);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
+                            ex);
+                }
+            });
+        }
+
+        public void notifyRequestCanceledAsync(IBinder token) {
+            @RequestStatus Integer lastStatus = mLastNotifiedStatus.get(token);
+            if (lastStatus != null && lastStatus == STATUS_CANCELED) {
+                return;
             }
+
+            mLastNotifiedStatus.put(token, STATUS_CANCELED);
+            mHandler.post(() -> {
+                try {
+                    mCallback.onRequestCanceled(token);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
+                            ex);
+                }
+            });
         }
     }
 
@@ -848,14 +785,21 @@
 
         @Override // Binder call
         public void requestState(IBinder token, int state, int flags) {
-            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
-                    "Permission required to request device state.");
+            final int callingPid = Binder.getCallingPid();
+            // Allow top processes to request a device state change
+            // If the calling process ID is not the top app, then we check if this process
+            // holds a permission to CONTROL_DEVICE_STATE
+            final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
+            if (topApp.getPid() != callingPid) {
+                getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
+                        "Permission required to request device state, "
+                                + "or the call must come from the top focused app.");
+            }
 
             if (token == null) {
                 throw new IllegalArgumentException("Request token must not be null.");
             }
 
-            final int callingPid = Binder.getCallingPid();
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
                 requestStateInternal(state, flags, callingPid, token);
@@ -866,14 +810,21 @@
 
         @Override // Binder call
         public void cancelRequest(IBinder token) {
-            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
-                    "Permission required to clear requested device state.");
+            final int callingPid = Binder.getCallingPid();
+            // Allow top processes to cancel a device state change
+            // If the calling process ID is not the top app, then we check if this process
+            // holds a permission to CONTROL_DEVICE_STATE
+            final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
+            if (topApp.getPid() != callingPid) {
+                getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
+                        "Permission required to cancel device state, "
+                                + "or the call must come from the top focused app.");
+            }
 
             if (token == null) {
                 throw new IllegalArgumentException("Request token must not be null.");
             }
 
-            final int callingPid = Binder.getCallingPid();
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
                 cancelRequestInternal(callingPid, token);
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequest.java b/services/core/java/com/android/server/devicestate/OverrideRequest.java
new file mode 100644
index 0000000..35a4c84
--- /dev/null
+++ b/services/core/java/com/android/server/devicestate/OverrideRequest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.devicestate;
+
+import android.hardware.devicestate.DeviceStateRequest;
+import android.os.IBinder;
+
+/**
+ * A request to override the state managed by {@link DeviceStateManagerService}.
+ *
+ * @see OverrideRequestController
+ */
+final class OverrideRequest {
+    private final IBinder mToken;
+    private final int mPid;
+    private final int mRequestedState;
+    @DeviceStateRequest.RequestFlags
+    private final int mFlags;
+
+    OverrideRequest(IBinder token, int pid, int requestedState,
+            @DeviceStateRequest.RequestFlags int flags) {
+        mToken = token;
+        mPid = pid;
+        mRequestedState = requestedState;
+        mFlags = flags;
+    }
+
+    IBinder getToken() {
+        return mToken;
+    }
+
+    int getPid() {
+        return mPid;
+    }
+
+    int getRequestedState() {
+        return mRequestedState;
+    }
+
+    @DeviceStateRequest.RequestFlags
+    int getFlags() {
+        return mFlags;
+    }
+}
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequestController.java b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
new file mode 100644
index 0000000..05c9eb2
--- /dev/null
+++ b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
@@ -0,0 +1,322 @@
+/*
+ * 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.devicestate;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.os.IBinder;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the lifecycle of override requests.
+ * <p>
+ * New requests are added with {@link #addRequest(OverrideRequest)} and are kept active until
+ * either:
+ * <ul>
+ *     <li>A new request is added with {@link #addRequest(OverrideRequest)}, in which case the
+ *     request will become suspended.</li>
+ *     <li>The request is cancelled with {@link #cancelRequest(IBinder)} or as a side effect
+ *     of other methods calls, such as {@link #handleProcessDied(int)}.</li>
+ * </ul>
+ */
+final class OverrideRequestController {
+    static final int STATUS_UNKNOWN = 0;
+    /**
+     * The request is the top-most request.
+     */
+    static final int STATUS_ACTIVE = 1;
+    /**
+     * The request is still present but is being superseded by another request.
+     */
+    static final int STATUS_SUSPENDED = 2;
+    /**
+     * The request is not longer valid.
+     */
+    static final int STATUS_CANCELED = 3;
+
+    @IntDef(prefix = {"STATUS_"}, value = {
+            STATUS_UNKNOWN,
+            STATUS_ACTIVE,
+            STATUS_SUSPENDED,
+            STATUS_CANCELED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface RequestStatus {}
+
+    static String statusToString(@RequestStatus int status) {
+        switch (status) {
+            case STATUS_ACTIVE:
+                return "ACTIVE";
+            case STATUS_SUSPENDED:
+                return "SUSPENDED";
+            case STATUS_CANCELED:
+                return "CANCELED";
+            case STATUS_UNKNOWN:
+                return "UNKNOWN";
+        }
+        throw new IllegalArgumentException("Unknown status: " + status);
+    }
+
+    private final StatusChangeListener mListener;
+    private final List<OverrideRequest> mTmpRequestsToCancel = new ArrayList<>();
+
+    // List of override requests with the most recent override request at the end.
+    private final ArrayList<OverrideRequest> mRequests = new ArrayList<>();
+
+    private boolean mStickyRequestsAllowed;
+    // List of override requests that have outlived their process and will only be cancelled through
+    // a call to cancelStickyRequests().
+    private final ArrayList<OverrideRequest> mStickyRequests = new ArrayList<>();
+
+    OverrideRequestController(@NonNull StatusChangeListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Sets sticky requests as either allowed or disallowed. When sticky requests are allowed a call
+     * to {@link #handleProcessDied(int)} will not result in the request being cancelled
+     * immediately. Instead, the request will be marked sticky and must be cancelled with a call
+     * to {@link #cancelStickyRequests()}.
+     */
+    void setStickyRequestsAllowed(boolean stickyRequestsAllowed) {
+        mStickyRequestsAllowed = stickyRequestsAllowed;
+        if (!mStickyRequestsAllowed) {
+            cancelStickyRequests();
+        }
+    }
+
+    /**
+     * Adds a request to the top of the stack and notifies the listener of all changes to request
+     * status as a result of this operation.
+     */
+    void addRequest(@NonNull OverrideRequest request) {
+        mRequests.add(request);
+        mListener.onStatusChanged(request, STATUS_ACTIVE);
+
+        if (mRequests.size() > 1) {
+            OverrideRequest prevRequest = mRequests.get(mRequests.size() - 2);
+            mListener.onStatusChanged(prevRequest, STATUS_SUSPENDED);
+        }
+    }
+
+    /**
+     * Cancels the request with the specified {@code token} and notifies the listener of all changes
+     * to request status as a result of this operation.
+     */
+    void cancelRequest(@NonNull IBinder token) {
+        int index = getRequestIndex(token);
+        if (index == -1) {
+            return;
+        }
+
+        OverrideRequest request = mRequests.remove(index);
+        if (index == mRequests.size() && mRequests.size() > 0) {
+            // We removed the current active request so we need to set the new active request
+            // before cancelling this request.
+            OverrideRequest newTop = getLast(mRequests);
+            mListener.onStatusChanged(newTop, STATUS_ACTIVE);
+        }
+        mListener.onStatusChanged(request, STATUS_CANCELED);
+    }
+
+    /**
+     * Cancels all requests that are currently marked sticky and notifies the listener of all
+     * changes to request status as a result of this operation.
+     *
+     * @see #setStickyRequestsAllowed(boolean)
+     */
+    void cancelStickyRequests() {
+        mTmpRequestsToCancel.clear();
+        mTmpRequestsToCancel.addAll(mStickyRequests);
+        cancelRequestsLocked(mTmpRequestsToCancel);
+    }
+
+    /**
+     * Returns {@code true} if this controller is current managing a request with the specified
+     * {@code token}, {@code false} otherwise.
+     */
+    boolean hasRequest(@NonNull IBinder token) {
+        return getRequestIndex(token) != -1;
+    }
+
+    /**
+     * Notifies the controller that the process with the specified {@code pid} has died. The
+     * controller will notify the listener of all changes to request status as a result of this
+     * operation.
+     */
+    void handleProcessDied(int pid) {
+        if (mRequests.isEmpty()) {
+            return;
+        }
+
+        mTmpRequestsToCancel.clear();
+        OverrideRequest prevActiveRequest = getLast(mRequests);
+        for (OverrideRequest request : mRequests) {
+            if (request.getPid() == pid) {
+                mTmpRequestsToCancel.add(request);
+            }
+        }
+
+        if (mStickyRequestsAllowed) {
+            // Do not cancel the requests now because sticky requests are allowed. These
+            // requests will be cancelled on a call to cancelStickyRequests().
+            mStickyRequests.addAll(mTmpRequestsToCancel);
+            return;
+        }
+
+        cancelRequestsLocked(mTmpRequestsToCancel);
+    }
+
+    /**
+     * Notifies the controller that the base state has changed. The controller will notify the
+     * listener of all changes to request status as a result of this change.
+     *
+     * @return {@code true} if calling this method has lead to a new active request, {@code false}
+     * otherwise.
+     */
+    boolean handleBaseStateChanged() {
+        if (mRequests.isEmpty()) {
+            return false;
+        }
+
+        mTmpRequestsToCancel.clear();
+        OverrideRequest prevActiveRequest = getLast(mRequests);
+        for (int i = 0; i < mRequests.size(); i++) {
+            OverrideRequest request = mRequests.get(i);
+            if ((request.getFlags() & DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES) != 0) {
+                mTmpRequestsToCancel.add(request);
+            }
+        }
+
+        final boolean newActiveRequest = cancelRequestsLocked(mTmpRequestsToCancel);
+        return newActiveRequest;
+    }
+
+    /**
+     * Notifies the controller that the set of supported states has changed. The controller will
+     * notify the listener of all changes to request status as a result of this change.
+     *
+     * @return {@code true} if calling this method has lead to a new active request, {@code false}
+     * otherwise.
+     */
+    boolean handleNewSupportedStates(int[] newSupportedStates) {
+        if (mRequests.isEmpty()) {
+            return false;
+        }
+
+        mTmpRequestsToCancel.clear();
+        for (int i = 0; i < mRequests.size(); i++) {
+            OverrideRequest request = mRequests.get(i);
+            if (!contains(newSupportedStates, request.getRequestedState())) {
+                mTmpRequestsToCancel.add(request);
+            }
+        }
+
+        final boolean newActiveRequest = cancelRequestsLocked(mTmpRequestsToCancel);
+        return newActiveRequest;
+    }
+
+    void dumpInternal(PrintWriter pw) {
+        final int requestCount = mRequests.size();
+        pw.println();
+        pw.println("Override requests: size=" + requestCount);
+        for (int i = 0; i < requestCount; i++) {
+            OverrideRequest overrideRequest = mRequests.get(i);
+            int status = (i == requestCount - 1) ? STATUS_ACTIVE : STATUS_SUSPENDED;
+            pw.println("  " + i + ": mPid=" + overrideRequest.getPid()
+                    + ", mRequestedState=" + overrideRequest.getRequestedState()
+                    + ", mFlags=" + overrideRequest.getFlags()
+                    + ", mStatus=" + statusToString(status));
+        }
+    }
+
+    /**
+     * Handles cancelling a set of requests. If the set of requests to cancel will lead to a new
+     * request becoming active this request will also be notified of its change in state.
+     *
+     * @return {@code true} if calling this method has lead to a new active request, {@code false}
+     * otherwise.
+     */
+    private boolean cancelRequestsLocked(List<OverrideRequest> requestsToCancel) {
+        if (requestsToCancel.isEmpty()) {
+            return false;
+        }
+
+        OverrideRequest prevActiveRequest = getLast(mRequests);
+        boolean causedNewRequestToBecomeActive = false;
+        mRequests.removeAll(requestsToCancel);
+        mStickyRequests.removeAll(requestsToCancel);
+        if (!mRequests.isEmpty()) {
+            OverrideRequest newActiveRequest = getLast(mRequests);
+            if (newActiveRequest != prevActiveRequest) {
+                mListener.onStatusChanged(newActiveRequest, STATUS_ACTIVE);
+                causedNewRequestToBecomeActive = true;
+            }
+        }
+
+        for (int i = 0; i < requestsToCancel.size(); i++) {
+            mListener.onStatusChanged(requestsToCancel.get(i), STATUS_CANCELED);
+        }
+        return causedNewRequestToBecomeActive;
+    }
+
+    private int getRequestIndex(@NonNull IBinder token) {
+        final int numberOfRequests = mRequests.size();
+        if (numberOfRequests == 0) {
+            return -1;
+        }
+
+        for (int i = 0; i < numberOfRequests; i++) {
+            OverrideRequest request = mRequests.get(i);
+            if (request.getToken() == token) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    @Nullable
+    private static <T> T getLast(List<T> list) {
+        return list.size() > 0 ? list.get(list.size() - 1) : null;
+    }
+
+    private static boolean contains(int[] array, int value) {
+        for (int i = 0; i < array.length; i++) {
+            if (array[i] == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public interface StatusChangeListener {
+        /**
+         * Notifies the listener of a change in request status. If a change within the controller
+         * causes one request to become active and one to become either suspended or cancelled, this
+         * method is guaranteed to be called with the active request first before the suspended or
+         * cancelled request.
+         */
+        void onStatusChanged(@NonNull OverrideRequest request, @RequestStatus int newStatus);
+    }
+}
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index 1acd5d0..9dd2f84 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -111,8 +111,8 @@
                 for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
                     layout.createDisplayLocked(
                             DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
-                            d.getIsDefault(),
-                            d.getEnabled());
+                            d.isDefaultDisplay(),
+                            d.isEnabled());
                 }
             }
         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
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/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 4c9d0f2..2ae5cbb 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -590,7 +590,7 @@
             newIndex = i - newStart;
             final float newBacklightVal;
             final float newNitsVal;
-            isLastValue = mRawBacklight[i] > mBacklightMaximum
+            isLastValue = mRawBacklight[i] >= mBacklightMaximum
                     || i >= mRawBacklight.length - 1;
             // Clamp beginning and end to valid backlight values.
             if (newIndex == 0) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
index 57f4486..2b52350 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
@@ -123,6 +123,17 @@
         return null;
     }
 
+    // String uniqueId -> DisplayDevice object with that given uniqueId
+    public DisplayDevice getByUniqueIdLocked(@NonNull String uniqueId) {
+        for (int i = mDisplayDevices.size() - 1; i >= 0; i--) {
+            final DisplayDevice displayDevice = mDisplayDevices.get(i);
+            if (displayDevice.getUniqueId().equals(uniqueId)) {
+                return displayDevice;
+            }
+        }
+        return null;
+    }
+
     private void handleDisplayDeviceAdded(DisplayDevice device) {
         synchronized (mSyncRoot) {
             DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index afd1889..73bcea6 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;
@@ -192,14 +190,16 @@
 
     private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
-    private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.1f;
+    // This value needs to be in sync with the threshold
+    // in RefreshRateConfigs::getFrameRateDivider.
+    private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.0009f;
 
     private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
     private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
     private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
     private static final int MSG_REQUEST_TRAVERSAL = 4;
     private static final int MSG_UPDATE_VIEWPORT = 5;
-    private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6;
+    private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATIONS = 6;
     private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7;
     private static final int MSG_DELIVER_DISPLAY_GROUP_EVENT = 8;
 
@@ -525,16 +525,29 @@
         final int newUserId = to.getUserIdentifier();
         final int userSerial = getUserManager().getUserSerialNumber(newUserId);
         synchronized (mSyncRoot) {
-            final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
-                    Display.DEFAULT_DISPLAY);
-            if (mCurrentUserId != newUserId) {
+            boolean userSwitching = mCurrentUserId != newUserId;
+            if (userSwitching) {
                 mCurrentUserId = newUserId;
-                BrightnessConfiguration config =
-                        mPersistentDataStore.getBrightnessConfiguration(userSerial);
-                displayPowerController.setBrightnessConfiguration(config);
-                handleSettingsChange();
             }
-            displayPowerController.onSwitchUser(newUserId);
+            mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
+                if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
+                    return;
+                }
+                final DisplayPowerController dpc = mDisplayPowerControllers.get(
+                        logicalDisplay.getDisplayIdLocked());
+                if (dpc == null) {
+                    return;
+                }
+                if (userSwitching) {
+                    BrightnessConfiguration config =
+                            getBrightnessConfigForDisplayWithPdsFallbackLocked(
+                            logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(),
+                            userSerial);
+                    dpc.setBrightnessConfiguration(config);
+                }
+                dpc.onSwitchUser(newUserId);
+            });
+            handleSettingsChange();
         }
     }
 
@@ -636,6 +649,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);
@@ -812,7 +828,7 @@
 
         // Override the refresh rate only if it is a divider of the current
         // refresh rate. This calculation needs to be in sync with the native code
-        // in RefreshRateConfigs::getRefreshRateDividerForUid
+        // in RefreshRateConfigs::getFrameRateDivider
         Display.Mode currentMode = info.getMode();
         float numPeriods = currentMode.getRefreshRate() / frameRateHz;
         float numPeriodsRound = Math.round(numPeriods);
@@ -1315,6 +1331,13 @@
         if (work != null) {
             mHandler.post(work);
         }
+        final int displayId = display.getDisplayIdLocked();
+        DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+        if (dpc != null) {
+            dpc.onDisplayChanged();
+        }
+        mPersistentDataStore.saveIfNeeded();
+        mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
         handleLogicalDisplayChangedLocked(display);
     }
 
@@ -1423,24 +1446,42 @@
         return mDisplayModeDirector.getModeSwitchingType();
     }
 
-    private void setBrightnessConfigurationForUserInternal(
-            @Nullable BrightnessConfiguration c, @UserIdInt int userId,
-            @Nullable String packageName) {
+    private void setBrightnessConfigurationForDisplayInternal(
+            @Nullable BrightnessConfiguration c, String uniqueId, @UserIdInt int userId,
+            String packageName) {
         validateBrightnessConfiguration(c);
         final int userSerial = getUserManager().getUserSerialNumber(userId);
         synchronized (mSyncRoot) {
             try {
-                mPersistentDataStore.setBrightnessConfigurationForUser(c, userSerial,
-                        packageName);
+                DisplayDevice displayDevice = mDisplayDeviceRepo.getByUniqueIdLocked(uniqueId);
+                if (displayDevice == null) {
+                    return;
+                }
+                mPersistentDataStore.setBrightnessConfigurationForDisplayLocked(c, displayDevice,
+                        userSerial, packageName);
             } finally {
                 mPersistentDataStore.saveIfNeeded();
             }
-            if (userId == mCurrentUserId) {
-                mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY).setBrightnessConfiguration(c);
+            if (userId != mCurrentUserId) {
+                return;
+            }
+            DisplayPowerController dpc = getDpcFromUniqueIdLocked(uniqueId);
+            if (dpc != null) {
+                dpc.setBrightnessConfiguration(c);
             }
         }
     }
 
+    private DisplayPowerController getDpcFromUniqueIdLocked(String uniqueId) {
+        final DisplayDevice displayDevice = mDisplayDeviceRepo.getByUniqueIdLocked(uniqueId);
+        final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayDevice);
+        if (logicalDisplay != null) {
+            final int displayId = logicalDisplay.getDisplayIdLocked();
+            return mDisplayPowerControllers.get(displayId);
+        }
+        return null;
+    }
+
     @VisibleForTesting
     void validateBrightnessConfiguration(BrightnessConfiguration config) {
         if (config == null) {
@@ -1463,13 +1504,22 @@
         return false;
     }
 
-    private void loadBrightnessConfiguration() {
+    private void loadBrightnessConfigurations() {
+        int userSerial = getUserManager().getUserSerialNumber(mContext.getUserId());
         synchronized (mSyncRoot) {
-            final int userSerial = getUserManager().getUserSerialNumber(mCurrentUserId);
-            BrightnessConfiguration config =
-                    mPersistentDataStore.getBrightnessConfiguration(userSerial);
-            mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY).setBrightnessConfiguration(
-                    config);
+            mLogicalDisplayMapper.forEachLocked((logicalDisplay) -> {
+                final String uniqueId =
+                        logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
+                final BrightnessConfiguration config =
+                        getBrightnessConfigForDisplayWithPdsFallbackLocked(uniqueId, userSerial);
+                if (config != null) {
+                    final DisplayPowerController dpc = mDisplayPowerControllers.get(
+                            logicalDisplay.getDisplayIdLocked());
+                    if (dpc != null) {
+                        dpc.setBrightnessConfiguration(config);
+                    }
+                }
+            });
         }
     }
 
@@ -1680,9 +1730,17 @@
         return SurfaceControl.getDisplayedContentSample(token, maxFrames, timestamp);
     }
 
-    void resetBrightnessConfiguration() {
-        setBrightnessConfigurationForUserInternal(null, mContext.getUserId(),
+    void resetBrightnessConfigurations() {
+        mPersistentDataStore.setBrightnessConfigurationForUser(null, mContext.getUserId(),
                 mContext.getPackageName());
+        mLogicalDisplayMapper.forEachLocked((logicalDisplay -> {
+            if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
+                return;
+            }
+            final String uniqueId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
+            setBrightnessConfigurationForDisplayInternal(null, uniqueId, mContext.getUserId(),
+                    mContext.getPackageName());
+        }));
     }
 
     void setAutoBrightnessLoggingEnabled(boolean enabled) {
@@ -1723,6 +1781,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 +1822,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.
@@ -2113,6 +2189,18 @@
         return display == null ? null : display.getPrimaryDisplayDeviceLocked();
     }
 
+    private BrightnessConfiguration getBrightnessConfigForDisplayWithPdsFallbackLocked(
+            String uniqueId, int userSerial) {
+        BrightnessConfiguration config =
+                mPersistentDataStore.getBrightnessConfigurationForDisplayLocked(
+                        uniqueId, userSerial);
+        if (config == null) {
+            // Get from global configurations
+            config = mPersistentDataStore.getBrightnessConfiguration(userSerial);
+        }
+        return config;
+    }
+
     private final class DisplayManagerHandler extends Handler {
         public DisplayManagerHandler(Looper looper) {
             super(looper, null, true /*async*/);
@@ -2154,8 +2242,8 @@
                     break;
                 }
 
-                case MSG_LOAD_BRIGHTNESS_CONFIGURATION:
-                    loadBrightnessConfiguration();
+                case MSG_LOAD_BRIGHTNESS_CONFIGURATIONS:
+                    loadBrightnessConfigurations();
                     break;
 
                 case MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
@@ -2770,6 +2858,19 @@
         @Override // Binder call
         public void setBrightnessConfigurationForUser(
                 BrightnessConfiguration c, @UserIdInt int userId, String packageName) {
+            mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
+                if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
+                    return;
+                }
+                final DisplayDevice displayDevice = logicalDisplay.getPrimaryDisplayDeviceLocked();
+                setBrightnessConfigurationForDisplay(c, displayDevice.getUniqueId(), userId,
+                        packageName);
+            });
+        }
+
+        @Override // Binder call
+        public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c,
+                String uniqueId, int userId, String packageName) {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
                     "Permission required to change the display's brightness configuration");
@@ -2777,21 +2878,19 @@
                 mContext.enforceCallingOrSelfPermission(
                         Manifest.permission.INTERACT_ACROSS_USERS,
                         "Permission required to change the display brightness"
-                        + " configuration of another user");
-            }
-            if (packageName != null && !validatePackageName(getCallingUid(), packageName)) {
-                packageName = null;
+                                + " configuration of another user");
             }
             final long token = Binder.clearCallingIdentity();
             try {
-                setBrightnessConfigurationForUserInternal(c, userId, packageName);
+                setBrightnessConfigurationForDisplayInternal(c, uniqueId, userId, packageName);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override // Binder call
-        public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) {
+        public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueId,
+                int userId) {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
                     "Permission required to read the display's brightness configuration");
@@ -2802,14 +2901,19 @@
                                 + " configuration of another user");
             }
             final long token = Binder.clearCallingIdentity();
+            final int userSerial = getUserManager().getUserSerialNumber(userId);
             try {
-                final int userSerial = getUserManager().getUserSerialNumber(userId);
                 synchronized (mSyncRoot) {
+                    // Get from per-display configurations
                     BrightnessConfiguration config =
-                            mPersistentDataStore.getBrightnessConfiguration(userSerial);
+                            getBrightnessConfigForDisplayWithPdsFallbackLocked(
+                                    uniqueId, userSerial);
                     if (config == null) {
-                        config = mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
-                                .getDefaultBrightnessConfiguration();
+                        // Get default configuration
+                        DisplayPowerController dpc = getDpcFromUniqueIdLocked(uniqueId);
+                        if (dpc != null) {
+                            config = dpc.getDefaultBrightnessConfiguration();
+                        }
                     }
                     return config;
                 }
@@ -2818,6 +2922,21 @@
             }
         }
 
+
+
+        @Override // Binder call
+        public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) {
+            final String uniqueId;
+            synchronized (mSyncRoot) {
+                DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked(
+                        Display.DEFAULT_DISPLAY).getPrimaryDisplayDeviceLocked();
+                uniqueId = displayDevice.getUniqueId();
+            }
+            return getBrightnessConfigurationForDisplay(uniqueId, userId);
+
+
+        }
+
         @Override // Binder call
         public BrightnessConfiguration getDefaultBrightnessConfiguration() {
             mContext.enforceCallingOrSelfPermission(
@@ -3086,7 +3205,7 @@
                 initializeDisplayPowerControllersLocked();
             }
 
-            mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
+            mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
         }
 
         @Override
@@ -3314,6 +3433,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..9412c93 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 , "");
     }
@@ -115,7 +120,7 @@
     }
 
     private int resetBrightnessConfiguration() {
-        mService.resetBrightnessConfiguration();
+        mService.resetBrightnessConfigurations();
         return 0;
     }
 
@@ -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..be4ec71 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -36,11 +36,17 @@
 import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.Temperature;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.IndentingPrintWriter;
@@ -52,6 +58,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;
@@ -60,7 +67,6 @@
 import com.android.server.sensors.SensorManagerInternal;
 import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
 import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
@@ -107,6 +113,7 @@
     private final UdfpsObserver mUdfpsObserver;
     private final SensorObserver mSensorObserver;
     private final HbmObserver mHbmObserver;
+    private final SkinThermalStatusObserver mSkinThermalStatusObserver;
     private final DeviceConfigInterface mDeviceConfig;
     private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
 
@@ -153,8 +160,9 @@
                 updateVoteLocked(displayId, priority, vote);
             }
         };
-        mSensorObserver = new SensorObserver(context, ballotBox);
+        mSensorObserver = new SensorObserver(context, ballotBox, injector);
         mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
+        mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
         mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
         mDeviceConfig = injector.getDeviceConfig();
         mAlwaysRespectAppRequest = false;
@@ -173,6 +181,7 @@
         mBrightnessObserver.observe(sensorManager);
         mSensorObserver.observe();
         mHbmObserver.observe();
+        mSkinThermalStatusObserver.observe();
         synchronized (mLock) {
             // We may have a listener already registered before the call to start, so go ahead and
             // notify them to pick up our newly initialized state.
@@ -605,6 +614,7 @@
             mUdfpsObserver.dumpLocked(pw);
             mSensorObserver.dumpLocked(pw);
             mHbmObserver.dumpLocked(pw);
+            mSkinThermalStatusObserver.dumpLocked(pw);
         }
     }
 
@@ -713,7 +723,6 @@
         return mUdfpsObserver;
     }
 
-
     @VisibleForTesting
     DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
             float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
@@ -949,16 +958,19 @@
         // user seeing the display flickering when the switches occur.
         public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
 
+        // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
+        public static final int PRIORITY_SKIN_TEMPERATURE = 9;
+
         // High-brightness-mode may need a specific range of refresh-rates to function properly.
-        public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
+        public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10;
 
         // The proximity sensor needs the refresh rate to be locked in order to function, so this is
         // set to a high priority.
-        public static final int PRIORITY_PROXIMITY = 10;
+        public static final int PRIORITY_PROXIMITY = 11;
 
         // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
         // to function, so this needs to be the highest priority of all votes.
-        public static final int PRIORITY_UDFPS = 11;
+        public static final int PRIORITY_UDFPS = 12;
 
         // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
         // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1053,6 +1065,8 @@
                     return "PRIORITY_PROXIMITY";
                 case PRIORITY_LOW_POWER_MODE:
                     return "PRIORITY_LOW_POWER_MODE";
+                case PRIORITY_SKIN_TEMPERATURE:
+                    return "PRIORITY_SKIN_TEMPERATURE";
                 case PRIORITY_UDFPS:
                     return "PRIORITY_UDFPS";
                 case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
@@ -2129,27 +2143,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 +2183,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 +2214,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();
+            }
         }
     }
 
@@ -2254,6 +2324,52 @@
         }
     }
 
+    private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
+        private final BallotBox mBallotBox;
+        private final Injector mInjector;
+
+        private @Temperature.ThrottlingStatus int mStatus = -1;
+
+        SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) {
+            mInjector = injector;
+            mBallotBox = ballotBox;
+        }
+
+        @Override
+        public void notifyThrottling(Temperature temp) {
+            mStatus = temp.getStatus();
+            if (mLoggingEnabled) {
+                Slog.d(TAG, "New thermal throttling status "
+                        + ", current thermal status = " + mStatus);
+            }
+            final Vote vote;
+            if (mStatus >= Temperature.THROTTLING_CRITICAL) {
+                vote = Vote.forRefreshRates(0f, 60f);
+            } else {
+                vote = null;
+            }
+            mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+        }
+
+        public void observe() {
+            IThermalService thermalService = mInjector.getThermalService();
+            if (thermalService == null) {
+                Slog.w(TAG, "Could not observe thermal status. Service not available");
+                return;
+            }
+            try {
+                thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to register thermal status listener", e);
+            }
+        }
+
+        void dumpLocked(PrintWriter writer) {
+            writer.println("  SkinThermalStatusObserver:");
+            writer.println("    mStatus: " + mStatus);
+        }
+    }
+
     private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
         public DeviceConfigDisplaySettings() {
         }
@@ -2413,6 +2529,10 @@
                 Handler handler, long flags);
 
         BrightnessInfo getBrightnessInfo(int displayId);
+
+        boolean isDozeState(Display d);
+
+        IThermalService getThermalService();
     }
 
     @VisibleForTesting
@@ -2465,6 +2585,20 @@
             return null;
         }
 
+        @Override
+        public boolean isDozeState(Display d) {
+            if (d == null) {
+                return false;
+            }
+            return Display.isDozeState(d.getState());
+        }
+
+        @Override
+        public IThermalService getThermalService() {
+            return IThermalService.Stub.asInterface(
+                    ServiceManager.getService(Context.THERMAL_SERVICE));
+        }
+
         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 1108937..abbe13a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2122,7 +2122,6 @@
 
     private void ignoreProximitySensorUntilChangedInternal() {
         if (!mIgnoreProximityUntilChanged
-                && mPowerRequest.useProximitySensor
                 && mProximity == PROXIMITY_POSITIVE) {
             // Only ignore if it is still reporting positive (near)
             mIgnoreProximityUntilChanged = true;
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 6af1923..147050c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -411,7 +411,7 @@
      * Updates the state of the screen and backlight asynchronously on a separate thread.
      */
     private final class PhotonicModulator extends Thread {
-        private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
+        private static final int INITIAL_SCREEN_STATE = Display.STATE_UNKNOWN;
         private static final float INITIAL_BACKLIGHT_FLOAT = PowerManager.BRIGHTNESS_INVALID_FLOAT;
 
         private final Object mLock = new Object();
@@ -494,7 +494,9 @@
                     if (!backlightChanged) {
                         mBacklightChangeInProgress = false;
                     }
-                    if (!stateChanged && !backlightChanged) {
+                    boolean valid = state != Display.STATE_UNKNOWN && !Float.isNaN(brightnessState);
+                    boolean changed = stateChanged || backlightChanged;
+                    if (!valid || !changed) {
                         try {
                             mLock.wait();
                         } catch (InterruptedException ex) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 1769712..67df565 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -326,7 +326,7 @@
             if (mActiveModeId != NO_DISPLAY_MODE_ID
                     && mActiveModeId != activeRecord.mMode.getModeId()) {
                 Slog.d(TAG, "The active mode was changed from SurfaceFlinger or the display"
-                        + "device.");
+                        + " device to " + activeRecord.mMode);
                 mActiveModeId = activeRecord.mMode.getModeId();
                 activeModeChanged = true;
                 sendTraversalRequestLocked();
@@ -601,8 +601,6 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
-                    mInfo.roundedCorners = RoundedCorners.fromResources(
-                            res, mInfo.width, mInfo.height);
                 } else {
                     if (!res.getBoolean(
                                 com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
@@ -620,6 +618,9 @@
                 mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
                         mInfo.uniqueId, mInfo.width, mInfo.height);
 
+                mInfo.roundedCorners = RoundedCorners.fromResources(
+                        res, mInfo.uniqueId, mInfo.width, mInfo.height);
+
                 if (mStaticDisplayInfo.isInternal) {
                     mInfo.type = Display.TYPE_INTERNAL;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 5186744..48eea89 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -230,9 +230,9 @@
                 info.rotation = mOverrideDisplayInfo.rotation;
                 info.displayCutout = mOverrideDisplayInfo.displayCutout;
                 info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
-                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/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 4c9a2d7..a931718 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -195,6 +195,9 @@
     }
 
     public LogicalDisplay getDisplayLocked(DisplayDevice device) {
+        if (device == null) {
+            return null;
+        }
         final int count = mLogicalDisplays.size();
         for (int i = 0; i < count; i++) {
             final LogicalDisplay display = mLogicalDisplays.valueAt(i);
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index c90ddf4..4b0d43b 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -63,6 +63,15 @@
  *      &lt;display unique-id="XXXXXXX">
  *          &lt;color-mode>0&lt;/color-mode>
  *          &lt;brightness-value>0&lt;/brightness-value>
+ *          &lt;brightness-configurations>
+ *              &lt;brightness-configuration user-serial="0" package-name="com.example"
+ *              timestamp="1234">
+ *                  &lt;brightness-curve description="some text">
+ *                      &lt;brightness-point lux="0" nits="13.25"/>
+ *                      &lt;brightness-point lux="20" nits="35.94"/>
+ *                  &lt;/brightness-curve>
+ *              &lt;/brightness-configuration>
+ *          &lt;/brightness-configurations>
  *      &lt;/display>
  *  &lt;/display-states>
  *  &lt;stable-device-values>
@@ -120,7 +129,8 @@
     private final StableDeviceValues mStableDeviceValues = new StableDeviceValues();
 
     // Brightness configuration by user
-    private BrightnessConfigurations mBrightnessConfigurations = new BrightnessConfigurations();
+    private BrightnessConfigurations mGlobalBrightnessConfigurations =
+            new BrightnessConfigurations();
 
     // True if the data has been loaded.
     private boolean mLoaded;
@@ -293,18 +303,44 @@
         }
     }
 
+    // Used for testing & reset
     public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userSerial,
             @Nullable String packageName) {
         loadIfNeeded();
-        if (mBrightnessConfigurations.setBrightnessConfigurationForUser(c, userSerial,
+        if (mGlobalBrightnessConfigurations.setBrightnessConfigurationForUser(c, userSerial,
                 packageName)) {
+
             setDirty();
         }
     }
 
+    public boolean setBrightnessConfigurationForDisplayLocked(BrightnessConfiguration configuration,
+            DisplayDevice device, int userSerial, String packageName) {
+        if (device == null || !device.hasStableUniqueId()) {
+            return false;
+        }
+        DisplayState state = getDisplayState(device.getUniqueId(), /*createIfAbsent*/ true);
+        if (state.setBrightnessConfiguration(configuration, userSerial, packageName)) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+
+    public BrightnessConfiguration getBrightnessConfigurationForDisplayLocked(
+            String uniqueDisplayId, int userSerial) {
+        loadIfNeeded();
+        DisplayState state = mDisplayStates.get(uniqueDisplayId);
+        if (state != null) {
+            return state.getBrightnessConfiguration(userSerial);
+        }
+        return null;
+    }
+
     public BrightnessConfiguration getBrightnessConfiguration(int userSerial) {
         loadIfNeeded();
-        return mBrightnessConfigurations.getBrightnessConfiguration(userSerial);
+        return mGlobalBrightnessConfigurations.getBrightnessConfiguration(userSerial);
     }
 
     private DisplayState getDisplayState(String uniqueId, boolean createIfAbsent) {
@@ -391,7 +427,7 @@
                 mStableDeviceValues.loadFromXml(parser);
             }
             if (parser.getName().equals(TAG_BRIGHTNESS_CONFIGURATIONS)) {
-                mBrightnessConfigurations.loadFromXml(parser);
+                mGlobalBrightnessConfigurations.loadFromXml(parser);
             }
         }
     }
@@ -470,7 +506,7 @@
         mStableDeviceValues.saveToXml(serializer);
         serializer.endTag(null, TAG_STABLE_DEVICE_VALUES);
         serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
-        mBrightnessConfigurations.saveToXml(serializer);
+        mGlobalBrightnessConfigurations.saveToXml(serializer);
         serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
         serializer.endTag(null, TAG_DISPLAY_MANAGER_STATE);
         serializer.endDocument();
@@ -493,14 +529,18 @@
         }
         pw.println("  StableDeviceValues:");
         mStableDeviceValues.dump(pw, "      ");
-        pw.println("  BrightnessConfigurations:");
-        mBrightnessConfigurations.dump(pw, "      ");
+        pw.println("  GlobalBrightnessConfigurations:");
+        mGlobalBrightnessConfigurations.dump(pw, "      ");
     }
 
     private static final class DisplayState {
         private int mColorMode;
         private float mBrightness;
 
+        // Brightness configuration by user
+        private BrightnessConfigurations mDisplayBrightnessConfigurations =
+                new BrightnessConfigurations();
+
         public boolean setColorMode(int colorMode) {
             if (colorMode == mColorMode) {
                 return false;
@@ -525,6 +565,16 @@
             return mBrightness;
         }
 
+        public boolean setBrightnessConfiguration(BrightnessConfiguration configuration,
+                int userSerial, String packageName) {
+            mDisplayBrightnessConfigurations.setBrightnessConfigurationForUser(
+                    configuration, userSerial, packageName);
+            return true;
+        }
+
+        public BrightnessConfiguration getBrightnessConfiguration(int userSerial) {
+            return mDisplayBrightnessConfigurations.mConfigurations.get(userSerial);
+        }
 
         public void loadFromXml(TypedXmlPullParser parser)
                 throws IOException, XmlPullParserException {
@@ -540,6 +590,9 @@
                         String brightness = parser.nextText();
                         mBrightness = Float.parseFloat(brightness);
                         break;
+                    case TAG_BRIGHTNESS_CONFIGURATIONS:
+                        mDisplayBrightnessConfigurations.loadFromXml(parser);
+                        break;
                 }
             }
         }
@@ -548,15 +601,21 @@
             serializer.startTag(null, TAG_COLOR_MODE);
             serializer.text(Integer.toString(mColorMode));
             serializer.endTag(null, TAG_COLOR_MODE);
+
             serializer.startTag(null, TAG_BRIGHTNESS_VALUE);
             serializer.text(Float.toString(mBrightness));
             serializer.endTag(null, TAG_BRIGHTNESS_VALUE);
 
+            serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
+            mDisplayBrightnessConfigurations.saveToXml(serializer);
+            serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
         }
 
         public void dump(final PrintWriter pw, final String prefix) {
             pw.println(prefix + "ColorMode=" + mColorMode);
             pw.println(prefix + "BrightnessValue=" + mBrightness);
+            pw.println(prefix + "DisplayBrightnessConfigurations: ");
+            mDisplayBrightnessConfigurations.dump(pw, prefix);
         }
     }
 
@@ -621,11 +680,11 @@
 
     private static final class BrightnessConfigurations {
         // Maps from a user ID to the users' given brightness configuration
-        private SparseArray<BrightnessConfiguration> mConfigurations;
+        private final SparseArray<BrightnessConfiguration> mConfigurations;
         // Timestamp of time the configuration was set.
-        private SparseLongArray mTimeStamps;
+        private final SparseLongArray mTimeStamps;
         // Package that set the configuration.
-        private SparseArray<String> mPackageNames;
+        private final SparseArray<String> mPackageNames;
 
         public BrightnessConfigurations() {
             mConfigurations = new SparseArray<>();
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index b7931c8..a592192 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,29 @@
             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() {
+            if (mSurface == null) {
+                return null;
+            }
+            return mSurface.getDefaultSize();
+        }
+
         @VisibleForTesting
         Surface getSurfaceLocked() {
             return mSurface;
@@ -362,6 +389,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/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectActionFromPlayback.java
similarity index 64%
copy from services/core/java/com/android/server/hdmi/DeviceSelectAction.java
copy to services/core/java/com/android/server/hdmi/DeviceSelectActionFromPlayback.java
index f6828d1..b2338e6 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectActionFromPlayback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 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.
@@ -18,23 +18,24 @@
 
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
-import android.hardware.hdmi.HdmiTvClient;
+import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
  * Handles an action that selects a logical device as a new active source.
  *
- * Triggered by {@link HdmiTvClient}, attempts to select the given target device
- * for a new active source. It does its best to wake up the target in standby mode
- * before issuing the command &gt;Set Stream path&lt;.
+ * Triggered by {@link HdmiPlaybackClient}, attempts to select the given target device
+ * for a new active source. A &gt;Routing Change&lt; command is issued in order to select
+ * the target device. If that doesn't succeed a &gt;Set Stream Path&lt; command is sent.
+ * It does its best to wake up the target in standby mode, before issuing the device
+ * select command.
  */
-final class DeviceSelectAction extends HdmiCecFeatureAction {
-    private static final String TAG = "DeviceSelect";
+final class DeviceSelectActionFromPlayback extends HdmiCecFeatureAction {
+    private static final String TAG = "DeviceSelectActionFromPlayback";
 
     // Time in milliseconds we wait for the device power status to switch to 'Standby'
     private static final int TIMEOUT_TRANSIT_TO_STANDBY_MS = 5 * 1000;
@@ -43,8 +44,8 @@
     private static final int TIMEOUT_POWER_ON_MS = 5 * 1000;
 
     // The number of times we try to wake up the target device before we give up
-    // and just send <Set Stream Path>.
-    private static final int LOOP_COUNTER_MAX = 20;
+    // and just send <Routing Change>.
+    private static final int LOOP_COUNTER_MAX = 2;
 
     // State in which we wait for <Report Power Status> to come in response to the command
     // <Give Device Power Status> we have sent.
@@ -52,7 +53,7 @@
     static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
 
     // State in which we wait for the device power status to switch to 'Standby'.
-    // We wait till the status becomes 'Standby' before we send <Set Stream Path>
+    // We wait till the status becomes 'Standby' before we send <Routing Change>
     // to wake up the device again.
     private static final int STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY = 2;
 
@@ -61,6 +62,16 @@
     @VisibleForTesting
     static final int STATE_WAIT_FOR_DEVICE_POWER_ON = 3;
 
+    // State in which we wait for <Active Source> to come in response to the command
+    // <Routing Change> we have sent.
+    @VisibleForTesting
+    static final int STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE = 4;
+
+    // State in which we wait for <Active Source> to come in response to the command
+    // <Set Stream Path> we have sent.
+    @VisibleForTesting
+    private static final int STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_SET_STREAM_PATH = 5;
+
     private final HdmiDeviceInfo mTarget;
     private final HdmiCecMessage mGivePowerStatus;
     private final boolean mIsCec20;
@@ -74,16 +85,16 @@
      * @param target target logical device that will be a new active source
      * @param callback callback object
      */
-    DeviceSelectAction(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target,
-                              IHdmiControlCallback callback) {
+    DeviceSelectActionFromPlayback(HdmiCecLocalDevicePlayback source, HdmiDeviceInfo target,
+            IHdmiControlCallback callback) {
         this(source, target, callback,
-             source.getDeviceInfo().getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0
-                     && target.getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
+                source.getDeviceInfo().getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0
+                        && target.getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
     }
 
     @VisibleForTesting
-    DeviceSelectAction(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target,
-                       IHdmiControlCallback callback, boolean isCec20) {
+    DeviceSelectActionFromPlayback(HdmiCecLocalDevicePlayback source, HdmiDeviceInfo target,
+            IHdmiControlCallback callback, boolean isCec20) {
         super(source, callback);
         mTarget = target;
         mGivePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
@@ -91,15 +102,18 @@
         mIsCec20 = isCec20;
     }
 
-    int getTargetAddress() {
+    private int getTargetAddress() {
         return mTarget.getLogicalAddress();
     }
 
+    private int getTargetPath() {
+        return mTarget.getPhysicalAddress();
+    }
+
     @Override
     public boolean start() {
-        // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
-        // The message is re-sent at the end of the action for devices that don't support 2.0.
-        sendSetStreamPath();
+        // This <Routing Change> message wakes up the target device in most cases.
+        sendRoutingChange();
 
         if (!mIsCec20) {
             queryDevicePowerStatus();
@@ -113,10 +127,12 @@
             if (targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
                 queryDevicePowerStatus();
             } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
-                finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
+                mState = STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE;
+                addTimer(mState, HdmiConfig.TIMEOUT_MS);
                 return true;
             }
         }
+
         mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
         addTimer(mState, HdmiConfig.TIMEOUT_MS);
         return true;
@@ -125,7 +141,7 @@
     private void queryDevicePowerStatus() {
         sendCommand(
                 mGivePowerStatus,
-                new SendMessageCallback() {
+                new HdmiControlService.SendMessageCallback() {
                     @Override
                     public void onSendCompleted(int error) {
                         if (error != SendMessageResult.SUCCESS) {
@@ -143,14 +159,14 @@
         }
         int opcode = cmd.getOpcode();
         byte[] params = cmd.getParams();
-        switch (mState) {
-            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
-                if (opcode == Constants.MESSAGE_REPORT_POWER_STATUS) {
-                    return handleReportPowerStatus(params[0]);
-                }
-                return false;
-            default:
-                break;
+        if (opcode == Constants.MESSAGE_ACTIVE_SOURCE) {
+            // The target device was successfully set as the active source
+            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
+            return true;
+        }
+        if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
+                && opcode == Constants.MESSAGE_REPORT_POWER_STATUS) {
+            return handleReportPowerStatus(params[0]);
         }
         return false;
     }
@@ -170,7 +186,7 @@
                 return true;
             case HdmiControlManager.POWER_STATUS_STANDBY:
                 if (mPowerStatusCounter == 0) {
-                    turnOnDevice();
+                    sendRoutingChange();
                     mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
                     addTimer(mState, TIMEOUT_POWER_ON_MS);
                 } else {
@@ -189,52 +205,47 @@
         return false;
     }
 
+    private void selectDevice() {
+        sendRoutingChange();
+        mState = STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE;
+        addTimer(mState, HdmiConfig.TIMEOUT_MS);
+    }
+
     @Override
-    public void handleTimerEvent(int timeoutState) {
+    void handleTimerEvent(int timeoutState) {
         if (mState != timeoutState) {
             Slog.w(TAG, "Timer in a wrong state. Ignored.");
             return;
         }
         switch (mState) {
             case STATE_WAIT_FOR_REPORT_POWER_STATUS:
-                if (tv().isPowerStandbyOrTransient()) {
-                    finishWithCallback(HdmiControlManager.RESULT_INCORRECT_MODE);
-                    return;
-                }
                 selectDevice();
+                addTimer(mState, HdmiConfig.TIMEOUT_MS);
                 break;
-            case STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY:
             case STATE_WAIT_FOR_DEVICE_POWER_ON:
                 mPowerStatusCounter++;
                 queryDevicePowerStatus();
                 mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
                 addTimer(mState, HdmiConfig.TIMEOUT_MS);
                 break;
+            case STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE:
+                sendSetStreamPath();
+                mState = STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_SET_STREAM_PATH;
+                addTimer(mState, HdmiConfig.TIMEOUT_MS);
+                break;
+            case STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_SET_STREAM_PATH:
+                finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
+                break;
         }
     }
 
-    private void turnOnDevice() {
-        if (!mIsCec20) {
-            sendUserControlPressedAndReleased(mTarget.getLogicalAddress(),
-                    HdmiCecKeycode.CEC_KEYCODE_POWER);
-            sendUserControlPressedAndReleased(mTarget.getLogicalAddress(),
-                    HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION);
-        }
-    }
-
-    private void selectDevice() {
-        if (!mIsCec20) {
-            sendSetStreamPath();
-        }
-        finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
+    private void sendRoutingChange() {
+        sendCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
+                playback().getActiveSource().physicalAddress, getTargetPath()));
     }
 
     private void sendSetStreamPath() {
-        // Turn the active source invalidated, which remains so till <Active Source> comes from
-        // the selected device.
-        tv().getActiveSource().invalidate();
-        tv().setActivePath(mTarget.getPhysicalAddress());
-        sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(
-                getSourceAddress(), mTarget.getPhysicalAddress()));
+        sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(),
+                getTargetPath()));
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectActionFromTv.java
similarity index 97%
rename from services/core/java/com/android/server/hdmi/DeviceSelectAction.java
rename to services/core/java/com/android/server/hdmi/DeviceSelectActionFromTv.java
index f6828d1..ff1a74a 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectActionFromTv.java
@@ -33,7 +33,7 @@
  * for a new active source. It does its best to wake up the target in standby mode
  * before issuing the command &gt;Set Stream path&lt;.
  */
-final class DeviceSelectAction extends HdmiCecFeatureAction {
+final class DeviceSelectActionFromTv extends HdmiCecFeatureAction {
     private static final String TAG = "DeviceSelect";
 
     // Time in milliseconds we wait for the device power status to switch to 'Standby'
@@ -74,7 +74,7 @@
      * @param target target logical device that will be a new active source
      * @param callback callback object
      */
-    DeviceSelectAction(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target,
+    DeviceSelectActionFromTv(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target,
                               IHdmiControlCallback callback) {
         this(source, target, callback,
              source.getDeviceInfo().getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0
@@ -82,7 +82,7 @@
     }
 
     @VisibleForTesting
-    DeviceSelectAction(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target,
+    DeviceSelectActionFromTv(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target,
                        IHdmiControlCallback callback, boolean isCec20) {
         super(source, callback);
         mTarget = target;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
index 444d74d..9437c4f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
@@ -27,7 +27,8 @@
 @VisibleForTesting
 public class HdmiCecAtomWriter {
 
-    private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
+    @VisibleForTesting
+    protected static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
     private static final int ERROR_CODE_UNKNOWN = -1;
 
     /**
@@ -103,26 +104,32 @@
             HdmiCecMessage message) {
         MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();
 
-        int keycode = message.getParams()[0];
-        if (keycode >= 0x1E && keycode <= 0x29) {
-            specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER;
-        } else {
-            specialArgs.mUserControlPressedCommand = keycode + 0x100;
+        if (message.getParams().length > 0) {
+            int keycode = message.getParams()[0];
+            if (keycode >= 0x1E && keycode <= 0x29) {
+                specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER;
+            } else {
+                specialArgs.mUserControlPressedCommand = keycode + 0x100;
+            }
         }
 
         return specialArgs;
     }
 
     /**
-     * Constructs method for constructing the special arguments for a <Feature Abort> message.
+     * Constructs the special arguments for a <Feature Abort> message.
      *
      * @param message The HDMI CEC message to log
      */
     private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) {
         MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();
 
-        specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte
-        specialArgs.mFeatureAbortReason = message.getParams()[1] + 10;
+        if (message.getParams().length > 0) {
+            specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte
+            if (message.getParams().length > 1) {
+                specialArgs.mFeatureAbortReason = message.getParams()[1] + 10;
+            }
+        }
 
         return specialArgs;
     }
@@ -135,8 +142,7 @@
      */
     private void messageReportedBase(MessageReportedGenericArgs genericArgs,
             MessageReportedSpecialArgs specialArgs) {
-        FrameworkStatsLog.write(
-                FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
+        writeHdmiCecMessageReportedAtom(
                 genericArgs.mUid,
                 genericArgs.mDirection,
                 genericArgs.mInitiatorLogicalAddress,
@@ -148,6 +154,26 @@
                 specialArgs.mFeatureAbortReason);
     }
 
+    /**
+     * Writes a HdmiCecMessageReported atom representing an incoming or outgoing HDMI-CEC message.
+     */
+    @VisibleForTesting
+    protected void writeHdmiCecMessageReportedAtom(int uid, int direction,
+            int initiatorLogicalAddress, int destinationLogicalAddress, int opcode,
+            int sendMessageResult, int userControlPressedCommand, int featureAbortOpcode,
+            int featureAbortReason) {
+        FrameworkStatsLog.write(
+                FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
+                uid,
+                direction,
+                initiatorLogicalAddress,
+                destinationLogicalAddress,
+                opcode,
+                sendMessageResult,
+                userControlPressedCommand,
+                featureAbortOpcode,
+                featureAbortReason);
+    }
 
     /**
      * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source.
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/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 3509062..f94d220 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -261,6 +261,20 @@
     }
 
     @ServiceThreadOnly
+    @VisibleForTesting
+    protected boolean isAlreadyActiveSource(HdmiDeviceInfo targetDevice, int targetAddress,
+            IHdmiControlCallback callback) {
+        ActiveSource active = getActiveSource();
+        if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON
+                && active.isValid()
+                && targetAddress == active.logicalAddress) {
+            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+            return true;
+        }
+        return false;
+    }
+
+    @ServiceThreadOnly
     @Constants.HandleMessageResult
     protected final int onMessage(HdmiCecMessage message) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 4376c9a..744436d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -124,6 +124,39 @@
                 String.valueOf(addr));
     }
 
+    /**
+     * Performs the action 'device select' or 'one touch play' initiated by a Playback device.
+     *
+     * @param id id of HDMI device to select
+     * @param callback callback object to report the result with
+     */
+    @ServiceThreadOnly
+    void deviceSelect(int id, IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        synchronized (mLock) {
+            if (id == getDeviceInfo().getId()) {
+                mService.oneTouchPlay(callback);
+                return;
+            }
+        }
+        HdmiDeviceInfo targetDevice = mService.getHdmiCecNetwork().getDeviceInfo(id);
+        if (targetDevice == null) {
+            invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
+            return;
+        }
+        int targetAddress = targetDevice.getLogicalAddress();
+        if (isAlreadyActiveSource(targetDevice, targetAddress, callback)) {
+            return;
+        }
+        if (!mService.isControlEnabled()) {
+            setActiveSource(targetDevice, "HdmiCecLocalDevicePlayback#deviceSelect()");
+            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
+            return;
+        }
+        removeAction(DeviceSelectActionFromPlayback.class);
+        addAndStartAction(new DeviceSelectActionFromPlayback(this, targetDevice, callback));
+    }
+
     @Override
     @ServiceThreadOnly
     void onHotplug(int portId, boolean connected) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index b087507..8d0a7bd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -242,11 +242,7 @@
             return;
         }
         int targetAddress = targetDevice.getLogicalAddress();
-        ActiveSource active = getActiveSource();
-        if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON
-                && active.isValid()
-                && targetAddress == active.logicalAddress) {
-            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+        if (isAlreadyActiveSource(targetDevice, targetAddress, callback)) {
             return;
         }
         if (targetAddress == Constants.ADDR_INTERNAL) {
@@ -263,8 +259,8 @@
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
         }
-        removeAction(DeviceSelectAction.class);
-        addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
+        removeAction(DeviceSelectActionFromTv.class);
+        addAndStartAction(new DeviceSelectActionFromTv(this, targetDevice, callback));
     }
 
     @ServiceThreadOnly
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 0c55138..6927094 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -405,7 +405,7 @@
     private TvInputManager mTvInputManager;
 
     @Nullable
-    private PowerManager mPowerManager;
+    private PowerManagerWrapper mPowerManager;
 
     @Nullable
     private Looper mIoLooper;
@@ -734,7 +734,7 @@
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
             mTvInputManager = (TvInputManager) getContext().getSystemService(
                     Context.TV_INPUT_SERVICE);
-            mPowerManager = getContext().getSystemService(PowerManager.class);
+            mPowerManager = new PowerManagerWrapper(getContext());
         } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
             runOnServiceThread(this::bootCompleted);
         }
@@ -755,7 +755,11 @@
     }
 
     @VisibleForTesting
-    protected PowerManager getPowerManager() {
+    void setPowerManager(PowerManagerWrapper powerManager) {
+        mPowerManager = powerManager;
+    }
+
+    PowerManagerWrapper getPowerManager() {
         return mPowerManager;
     }
 
@@ -1680,13 +1684,9 @@
                         Slog.e(TAG, "Callback cannot be null");
                         return;
                     }
-                    if (isPowerStandby()) {
-                        Slog.e(TAG, "Device is in standby. Not handling deviceSelect");
-                        invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
-                        return;
-                    }
                     HdmiCecLocalDeviceTv tv = tv();
-                    if (tv == null) {
+                    HdmiCecLocalDevicePlayback playback = playback();
+                    if (tv == null && playback == null) {
                         if (!mAddressAllocated) {
                             mSelectRequestBuffer.set(SelectRequestBuffer.newDeviceSelect(
                                     HdmiControlService.this, deviceId, callback));
@@ -1699,20 +1699,24 @@
                         invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
                         return;
                     }
-                    HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId);
-                    if (device != null) {
-                        if (device.getPortId() == tv.getActivePortId()) {
-                            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+                    if (tv != null) {
+                        HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId);
+                        if (device != null) {
+                            if (device.getPortId() == tv.getActivePortId()) {
+                                invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+                                return;
+                            }
+                            // Upon selecting MHL device, we send RAP[Content On] to wake up
+                            // the connected mobile device, start routing control to switch ports.
+                            // callback is handled by MHL action.
+                            device.turnOn(callback);
+                            tv.doManualPortSwitching(device.getPortId(), null);
                             return;
                         }
-                        // Upon selecting MHL device, we send RAP[Content On] to wake up
-                        // the connected mobile device, start routing control to switch ports.
-                        // callback is handled by MHL action.
-                        device.turnOn(callback);
-                        tv.doManualPortSwitching(device.getPortId(), null);
+                        tv.deviceSelect(deviceId, callback);
                         return;
                     }
-                    tv.deviceSelect(deviceId, callback);
+                    playback.deviceSelect(deviceId, callback);
                 }
             });
         }
@@ -1727,11 +1731,6 @@
                         Slog.e(TAG, "Callback cannot be null");
                         return;
                     }
-                    if (isPowerStandby()) {
-                        Slog.e(TAG, "Device is in standby. Not handling portSelect");
-                        invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
-                        return;
-                    }
                     HdmiCecLocalDeviceTv tv = tv();
                     if (tv != null) {
                         tv.doManualPortSwitching(portId, callback);
@@ -3158,7 +3157,7 @@
         });
     }
 
-    private boolean canGoToStandby() {
+    boolean canGoToStandby() {
         for (HdmiCecLocalDevice device : mHdmiCecNetwork.getLocalDeviceList()) {
             if (!device.canGoToStandby()) return false;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index e52e32a..a9b5214 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
@@ -92,6 +92,9 @@
         pw.println("      Sets the System Audio Mode feature on or off on TV devices");
         pw.println("  setarc [on|off]");
         pw.println("      Sets the ARC feature on or off on TV devices");
+        pw.println("  deviceselect <device id>");
+        pw.println("      Switch to device with given id");
+        pw.println("      The device's id is represented by its logical address.");
     }
 
     private int handleShellCommand(String cmd) throws RemoteException {
@@ -110,12 +113,30 @@
                 return setSystemAudioMode(pw);
             case "setarc":
                 return setArcMode(pw);
+            case "deviceselect":
+                return deviceSelect(pw);
         }
 
         getErrPrintWriter().println("Unhandled command: " + cmd);
         return 1;
     }
 
+    private int deviceSelect(PrintWriter pw) throws RemoteException {
+        if (getRemainingArgsCount() != 1) {
+            throw new IllegalArgumentException("Expected exactly 1 argument.");
+        }
+        int deviceId = Integer.parseInt(getNextArg());
+
+        pw.print("Sending Device Select...");
+        mBinderService.deviceSelect(deviceId, mHdmiControlCallback);
+
+        if (!receiveCallback("Device Select")) {
+            return 1;
+        }
+
+        return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
+    }
+
     private int oneTouchPlay(PrintWriter pw) throws RemoteException {
         pw.print("Sending One Touch Play...");
         mBinderService.oneTouchPlay(mHdmiControlCallback);
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 4c4c978..6fd7a72 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -237,15 +237,15 @@
     }
 
     private void mayCancelDeviceSelect(int address) {
-        List<DeviceSelectAction> actions = getActions(DeviceSelectAction.class);
+        List<DeviceSelectActionFromTv> actions = getActions(DeviceSelectActionFromTv.class);
         if (actions.isEmpty()) {
             return;
         }
 
         // Should have only one Device Select Action
-        DeviceSelectAction action = actions.get(0);
+        DeviceSelectActionFromTv action = actions.get(0);
         if (action.getTargetAddress() == address) {
-            removeAction(DeviceSelectAction.class);
+            removeAction(DeviceSelectActionFromTv.class);
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java b/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
new file mode 100644
index 0000000..f081068
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
@@ -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.hdmi;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+
+/**
+ * Abstraction around {@link PowerManager} to allow faking PowerManager in tests.
+ */
+public class PowerManagerWrapper {
+    private static final String TAG = "PowerManagerWrapper";
+
+    private final PowerManager mPowerManager;
+
+    public PowerManagerWrapper(Context context) {
+        mPowerManager = context.getSystemService(PowerManager.class);
+    }
+
+    boolean isInteractive() {
+        return mPowerManager.isInteractive();
+    }
+
+    void wakeUp(long time, int reason, String details) {
+        mPowerManager.wakeUp(time, reason, details);
+    }
+
+    void goToSleep(long time, int reason, int flags) {
+        mPowerManager.goToSleep(time, reason, flags);
+    }
+
+    WakeLock newWakeLock(int levelAndFlags, String tag) {
+        return mPowerManager.newWakeLock(levelAndFlags, tag);
+    }
+}
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 c553176..eb457c9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -180,7 +180,7 @@
     private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
 
     public static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
-            SystemProperties.getBoolean("persist.debug.per_window_input_rotation", true);
+            SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
 
     // Pointer to native input manager service object.
     private final long mPtr;
@@ -665,12 +665,10 @@
      */
     @Override // Binder call
     public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
-        if (keyCodes == null) {
-            throw new IllegalArgumentException("keyCodes must not be null.");
-        }
-        if (keyExists == null || keyExists.length < keyCodes.length) {
-            throw new IllegalArgumentException("keyExists must not be null and must be at "
-                    + "least as large as keyCodes.");
+        Objects.requireNonNull(keyCodes, "keyCodes must not be null");
+        Objects.requireNonNull(keyExists, "keyExists must not be null");
+        if (keyExists.length < keyCodes.length) {
+            throw new IllegalArgumentException("keyExists must be at least as large as keyCodes");
         }
 
         return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
@@ -685,7 +683,7 @@
      */
     public boolean transferTouch(IBinder destChannelToken) {
         // TODO(b/162194035): Replace this with a SPY window
-        Objects.requireNonNull(destChannelToken, "destChannelToken must not be null.");
+        Objects.requireNonNull(destChannelToken, "destChannelToken must not be null");
         return nativeTransferTouch(mPtr, destChannelToken);
     }
 
@@ -696,9 +694,7 @@
      * @return The input channel.
      */
     public InputChannel monitorInput(String inputChannelName, int displayId) {
-        if (inputChannelName == null) {
-            throw new IllegalArgumentException("inputChannelName must not be null.");
-        }
+        Objects.requireNonNull(inputChannelName, "inputChannelName not be null");
 
         if (displayId < Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("displayId must >= 0.");
@@ -722,7 +718,6 @@
                 "monitorInputRegion()")) {
             throw new SecurityException("Requires MONITOR_INPUT permission");
         }
-
         Objects.requireNonNull(inputChannelName, "inputChannelName must not be null.");
 
         if (displayId < Display.DEFAULT_DISPLAY) {
@@ -755,10 +750,7 @@
      * @param connectionToken The input channel to unregister.
      */
     public void removeInputChannel(IBinder connectionToken) {
-        if (connectionToken == null) {
-            throw new IllegalArgumentException("connectionToken must not be null.");
-        }
-
+        Objects.requireNonNull(connectionToken, "connectionToken must not be null");
         nativeRemoveInputChannel(mPtr, connectionToken);
     }
 
@@ -830,9 +822,7 @@
     }
 
     private boolean injectInputEventInternal(InputEvent event, int mode) {
-        if (event == null) {
-            throw new IllegalArgumentException("event must not be null");
-        }
+        Objects.requireNonNull(event, "event must not be null");
         if (mode != InputEventInjectionSync.NONE
                 && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
                 && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
@@ -900,6 +890,7 @@
 
     @Override // Binder call
     public VerifiedInputEvent verifyInputEvent(InputEvent event) {
+        Objects.requireNonNull(event, "event must not be null");
         return nativeVerifyInputEvent(mPtr, event);
     }
 
@@ -976,9 +967,7 @@
 
     @Override // Binder call
     public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
+        Objects.requireNonNull(listener, "listener must not be null");
 
         synchronized (mInputDevicesLock) {
             int callingPid = Binder.getCallingPid();
@@ -1173,9 +1162,7 @@
     @Override // Binder call & native callback
     public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
             int surfaceRotation) {
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
+        Objects.requireNonNull(inputDeviceDescriptor, "inputDeviceDescriptor must not be null");
 
         synchronized (mDataStore) {
             return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
@@ -1189,12 +1176,8 @@
                 "setTouchCalibrationForInputDevice()")) {
             throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
         }
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
-        if (calibration == null) {
-            throw new IllegalArgumentException("calibration must not be null");
-        }
+        Objects.requireNonNull(inputDeviceDescriptor, "inputDeviceDescriptor must not be null");
+        Objects.requireNonNull(calibration, "calibration must not be null");
         if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
             throw new IllegalArgumentException("surfaceRotation value out of bounds");
         }
@@ -1231,9 +1214,7 @@
                 "registerTabletModeChangedListener()")) {
             throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
         }
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
+        Objects.requireNonNull(listener, "event must not be null");
 
         synchronized (mTabletModeLock) {
             final int callingPid = Binder.getCallingPid();
@@ -1417,9 +1398,8 @@
 
     @Override // Binder call
     public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
-        if (keyboardLayoutDescriptor == null) {
-            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
-        }
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
 
         final KeyboardLayout[] result = new KeyboardLayout[1];
         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
@@ -1566,9 +1546,8 @@
      * descriptor for ids that aren't useful (such as the default 0, 0).
      */
     private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
-        if (identifier == null || identifier.getDescriptor() == null) {
-            throw new IllegalArgumentException("identifier and descriptor must not be null");
-        }
+        Objects.requireNonNull(identifier, "identifier must not be null");
+        Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null");
 
         if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
             return identifier.getDescriptor();
@@ -1606,9 +1585,9 @@
                 "setCurrentKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-        if (keyboardLayoutDescriptor == null) {
-            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
-        }
+
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
 
         String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
@@ -1645,9 +1624,8 @@
                 "addKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-        if (keyboardLayoutDescriptor == null) {
-            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
-        }
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
 
         String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
@@ -1674,9 +1652,8 @@
                 "removeKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-        if (keyboardLayoutDescriptor == null) {
-            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
-        }
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
 
         String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
@@ -1762,9 +1739,7 @@
 
     @Override
     public void requestPointerCapture(IBinder inputChannelToken, boolean enabled) {
-        if (inputChannelToken == null) {
-            return;
-        }
+        Objects.requireNonNull(inputChannelToken, "event must not be null");
 
         nativeRequestPointerCapture(mPtr, inputChannelToken, enabled);
     }
@@ -2368,10 +2343,7 @@
             Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid="
                     + Binder.getCallingPid());
         }
-        if (listener == null) {
-            Slog.e(TAG, "listener must not be null");
-            return false;
-        }
+        Objects.requireNonNull(listener, "listener must not be null");
 
         synchronized (mInputDevicesLock) {
             int callingPid = Binder.getCallingPid();
@@ -2403,9 +2375,7 @@
                     + Binder.getCallingPid());
         }
 
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
+        Objects.requireNonNull(listener, "listener must not be null");
 
         synchronized (mInputDevicesLock) {
             int callingPid = Binder.getCallingPid();
@@ -3244,9 +3214,7 @@
 
         @Override
         public void sendInputEvent(InputEvent event, int policyFlags) {
-            if (event == null) {
-                throw new IllegalArgumentException("event must not be null");
-            }
+            Objects.requireNonNull(event, "event must not be null");
 
             synchronized (mInputFilterLock) {
                 if (!mDisconnected) {
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/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 35c0e9a..2813236 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -58,10 +58,10 @@
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
-import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.UiThread;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -152,12 +152,9 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.inputmethod.CallbackUtils;
-import com.android.internal.inputmethod.IBooleanResultCallback;
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
 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;
@@ -182,6 +179,7 @@
 import com.android.internal.view.InlineSuggestionsRequestInfo;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -262,6 +260,7 @@
 
     private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
     private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
+    private static final String HANDLER_THREAD_NAME = "android.imms";
 
     /**
      * Binding flags for establishing connection to the {@link InputMethodService}.
@@ -1592,7 +1591,12 @@
         mIPackageManager = AppGlobals.getPackageManager();
         mContext = context;
         mRes = context.getResources();
-        mHandler = new Handler(this);
+        // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
+        // additional subtypes in switchUserOnHandlerLocked().
+        final ServiceThread thread = new ServiceThread(
+                HANDLER_THREAD_NAME, Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+        thread.start();
+        mHandler = Handler.createAsync(thread.getLooper(), this);
         // Note: SettingsObserver doesn't register observers in its constructor.
         mSettingsObserver = new SettingsObserver(mHandler);
         mIWindowManager = IWindowManager.Stub.asInterface(
@@ -1601,7 +1605,7 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId);
-        mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
+        mCaller = new HandlerCaller(context, thread.getLooper(), new HandlerCaller.Callback() {
             @Override
             public void executeMessage(Message msg) {
                 handleMessage(msg);
@@ -2580,14 +2584,12 @@
         }
 
         if (mCurToken != null) {
-            try {
-                if (DEBUG) {
-                    Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
-                            + mCurTokenDisplayId);
-                }
-                mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
-            } catch (RemoteException e) {
+            if (DEBUG) {
+                Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+                        + mCurTokenDisplayId);
             }
+            mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
+                    false /* animateExit */, mCurTokenDisplayId);
             // Set IME window status as invisible when unbind current method.
             mImeWindowVis = 0;
             mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
@@ -4121,6 +4123,18 @@
         }
     }
 
+    /** Called right after {@link IInputMethod#showSoftInput}. */
+    private void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
+            @SoftInputShowHideReason int reason) {
+        final WindowManagerInternal.ImeTargetInfo info =
+                mWindowManagerInternal.onToggleImeRequested(
+                        show, mCurFocusedWindow, requestToken, mCurTokenDisplayId);
+        mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
+                mCurFocusedWindowClient, mCurAttribute, info.focusedWindowName,
+                mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
+                info.requestWindowName, info.imeControlTargetName, info.imeLayerTargetName));
+    }
+
     @BinderThread
     private void hideMySoftInput(@NonNull IBinder token, int flags) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
@@ -4159,7 +4173,7 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
-    void setEnabledSessionInMainThread(SessionState session) {
+    void setEnabledSessionInHandlerThread(SessionState session) {
         if (mEnabledSession != session) {
             if (mEnabledSession != null && mEnabledSession.session != null) {
                 try {
@@ -4179,7 +4193,7 @@
         }
     }
 
-    @MainThread
+    @UiThread
     @Override
     public boolean handleMessage(Message msg) {
         SomeArgs args;
@@ -4239,18 +4253,11 @@
                     if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
                             + args.arg3 + ", " + msg.arg1 + ", " + args.arg2 + ") for reason: "
                             + InputMethodDebug.softInputDisplayReasonToString(reason));
+                    final IBinder token = (IBinder) args.arg3;
                     ((IInputMethod) args.arg1).showSoftInput(
-                            (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
-                    mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
-                            mCurFocusedWindowClient, mCurAttribute,
-                            mWindowManagerInternal.getWindowName(mCurFocusedWindow),
-                            mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
-                            mWindowManagerInternal.getWindowName(
-                                    mShowRequestWindowMap.get(args.arg3)),
-                            mWindowManagerInternal.getImeControlTargetNameForLogging(
-                                    mCurTokenDisplayId),
-                            mWindowManagerInternal.getImeTargetNameForLogging(
-                                    mCurTokenDisplayId)));
+                            token, msg.arg1 /* flags */, (ResultReceiver) args.arg2);
+                    final IBinder requestToken = mShowRequestWindowMap.get(token);
+                    onShowHideSoftInputRequested(true /* show */, requestToken, reason);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -4262,18 +4269,11 @@
                     if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
                             + args.arg3 + ", " + args.arg2 + ") for reason: "
                             + InputMethodDebug.softInputDisplayReasonToString(reason));
+                    final IBinder token = (IBinder) args.arg3;
                     ((IInputMethod)args.arg1).hideSoftInput(
-                            (IBinder) args.arg3, 0, (ResultReceiver)args.arg2);
-                    mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
-                            mCurFocusedWindowClient, mCurAttribute,
-                            mWindowManagerInternal.getWindowName(mCurFocusedWindow),
-                            mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
-                            mWindowManagerInternal.getWindowName(
-                                    mHideRequestWindowMap.get(args.arg3)),
-                            mWindowManagerInternal.getImeControlTargetNameForLogging(
-                                    mCurTokenDisplayId),
-                            mWindowManagerInternal.getImeTargetNameForLogging(
-                                    mCurTokenDisplayId)));
+                            token, 0 /* flags */, (ResultReceiver) args.arg2);
+                    final IBinder requestToken = mHideRequestWindowMap.get(token);
+                    onShowHideSoftInputRequested(false /* show */, requestToken, reason);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -4356,7 +4356,7 @@
                 final IInputContext inputContext = (IInputContext) args.arg3;
                 final EditorInfo editorInfo = (EditorInfo) args.arg4;
                 try {
-                    setEnabledSessionInMainThread(session);
+                    setEnabledSessionInHandlerThread(session);
                     session.method.startInput(startInputToken, inputContext, missingMethods,
                             editorInfo, restarting);
                 } catch (RemoteException e) {
@@ -5837,9 +5837,15 @@
         @BinderThread
         @Override
         public void createInputContentUriToken(Uri contentUri, String packageName,
-                IInputContentUriTokenResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback,
-                    () -> mImms.createInputContentUriToken(mToken, contentUri, packageName));
+                AndroidFuture future /* T=IBinder */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<IBinder> typedFuture = future;
+            try {
+                typedFuture.complete(mImms.createInputContentUriToken(
+                        mToken, contentUri, packageName).asBinder());
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
@@ -5850,28 +5856,55 @@
 
         @BinderThread
         @Override
-        public void setInputMethod(String id, IVoidResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback, () -> mImms.setInputMethod(mToken, id));
+        public void setInputMethod(String id, AndroidFuture future /* T=Void */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Void> typedFuture = future;
+            try {
+                mImms.setInputMethod(mToken, id);
+                typedFuture.complete(null);
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
         @Override
         public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype,
-                IVoidResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback,
-                    () -> mImms.setInputMethodAndSubtype(mToken, id, subtype));
+                AndroidFuture future /* T=Void */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Void> typedFuture = future;
+            try {
+                mImms.setInputMethodAndSubtype(mToken, id, subtype);
+                typedFuture.complete(null);
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
         @Override
-        public void hideMySoftInput(int flags, IVoidResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback, () -> mImms.hideMySoftInput(mToken, flags));
+        public void hideMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Void> typedFuture = future;
+            try {
+                mImms.hideMySoftInput(mToken, flags);
+                typedFuture.complete(null);
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
         @Override
-        public void showMySoftInput(int flags, IVoidResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback, () -> mImms.showMySoftInput(mToken, flags));
+        public void showMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Void> typedFuture = future;
+            try {
+                mImms.showMySoftInput(mToken, flags);
+                typedFuture.complete(null);
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
@@ -5882,24 +5915,39 @@
 
         @BinderThread
         @Override
-        public void switchToPreviousInputMethod(IBooleanResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback, () -> mImms.switchToPreviousInputMethod(mToken));
+        public void switchToPreviousInputMethod(AndroidFuture future /* T=Boolean */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Boolean> typedFuture = future;
+            try {
+                typedFuture.complete(mImms.switchToPreviousInputMethod(mToken));
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
         @Override
         public void switchToNextInputMethod(boolean onlyCurrentIme,
-                IBooleanResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback,
-                    () -> mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
+                AndroidFuture future /* T=Boolean */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Boolean> typedFuture = future;
+            try {
+                typedFuture.complete(mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
         @Override
-        public void shouldOfferSwitchingToNextInputMethod(
-                IBooleanResultCallback resultCallback) {
-            CallbackUtils.onResult(resultCallback,
-                    () -> mImms.shouldOfferSwitchingToNextInputMethod(mToken));
+        public void shouldOfferSwitchingToNextInputMethod(AndroidFuture future /* T=Boolean */) {
+            @SuppressWarnings("unchecked")
+            final AndroidFuture<Boolean> typedFuture = future;
+            try {
+                typedFuture.complete(mImms.shouldOfferSwitchingToNextInputMethod(mToken));
+            } catch (Throwable e) {
+                typedFuture.completeExceptionally(e);
+            }
         }
 
         @BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 73baf79..b8bb399 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -200,6 +200,7 @@
             final Window w = mSwitchingDialog.getWindow();
             final WindowManager.LayoutParams attrs = w.getAttributes();
             w.setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+            w.setHideOverlayWindows(true);
             // Use an alternate token for the dialog for that window manager can group the token
             // with other IME windows based on type vs. grouping based on whichever token happens
             // to get selected by the system later on.
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 7b5a635..cd26fb5 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -1385,7 +1385,7 @@
 
                 ipw.println("Event Log:");
                 ipw.increaseIndent();
-                EVENT_LOG.iterate(manager.getName(), ipw::println);
+                EVENT_LOG.iterate(ipw::println, manager.getName());
                 ipw.decreaseIndent();
                 return;
             }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index 3da5a43..489b9b3 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -30,8 +30,6 @@
 import android.compat.annotation.EnabledAfter;
 import android.content.Context;
 import android.content.Intent;
-import android.hardware.contexthub.V1_0.ContextHubMsg;
-import android.hardware.contexthub.V1_0.Result;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubManager;
 import android.hardware.location.ContextHubTransaction;
@@ -383,23 +381,20 @@
                 checkNanoappPermsAsync();
             }
 
-            ContextHubMsg messageToNanoApp =
-                    ContextHubServiceUtil.createHidlContextHubMessage(mHostEndPointId, message);
-
-            int contextHubId = mAttachedContextHubInfo.getId();
             try {
-                result = mContextHubProxy.getHub().sendMessageToHub(contextHubId, messageToNanoApp);
+                result = mContextHubProxy.sendMessageToContextHub(
+                    mHostEndPointId, mAttachedContextHubInfo.getId(), message);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException in sendMessageToNanoApp (target hub ID = "
-                        + contextHubId + ")", e);
-                result = Result.UNKNOWN_FAILURE;
+                        + mAttachedContextHubInfo.getId() + ")", e);
+                result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
             }
         } else {
             Log.e(TAG, "Failed to send message to nanoapp: client connection is closed");
-            result = Result.UNKNOWN_FAILURE;
+            result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
         }
 
-        return ContextHubServiceUtil.toTransactionResult(result);
+        return result;
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
index e3522f6..41a406ce 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.hardware.contexthub.V1_0.ContextHubMsg;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.IContextHubClient;
 import android.hardware.location.IContextHubClientCallback;
@@ -227,37 +226,37 @@
      * Handles a message sent from a nanoapp.
      *
      * @param contextHubId the ID of the hub where the nanoapp sent the message from
+     * @param hostEndpointId The host endpoint ID of the client that this message is for.
      * @param message the message send by a nanoapp
      * @param nanoappPermissions the set of permissions the nanoapp holds
      * @param messagePermissions the set of permissions that should be used for attributing
      * permissions when this message is consumed by a client
      */
     /* package */ void onMessageFromNanoApp(
-            int contextHubId, ContextHubMsg message, List<String> nanoappPermissions,
-            List<String> messagePermissions) {
-        NanoAppMessage clientMessage = ContextHubServiceUtil.createNanoAppMessage(message);
-
+            int contextHubId, short hostEndpointId, NanoAppMessage message,
+            List<String> nanoappPermissions, List<String> messagePermissions) {
         if (DEBUG_LOG_ENABLED) {
-            Log.v(TAG, "Received " + clientMessage);
+            Log.v(TAG, "Received " + message);
         }
 
-        if (clientMessage.isBroadcastMessage()) {
+        if (message.isBroadcastMessage()) {
             // Broadcast messages shouldn't be sent with any permissions tagged per CHRE API
             // requirements.
             if (!messagePermissions.isEmpty()) {
-                Log.wtf(TAG, "Received broadcast message with permissions from " + message.appName);
+                Log.wtf(TAG, "Received broadcast message with permissions from "
+                        + message.getNanoAppId());
             }
 
             broadcastMessage(
-                    contextHubId, clientMessage, nanoappPermissions, messagePermissions);
+                    contextHubId, message, nanoappPermissions, messagePermissions);
         } else {
-            ContextHubClientBroker proxy = mHostEndPointIdToClientMap.get(message.hostEndPoint);
+            ContextHubClientBroker proxy = mHostEndPointIdToClientMap.get(hostEndpointId);
             if (proxy != null) {
                 proxy.sendMessageToClient(
-                        clientMessage, nanoappPermissions, messagePermissions);
+                        message, nanoappPermissions, messagePermissions);
             } else {
                 Log.e(TAG, "Cannot send message to unregistered client (host endpoint ID = "
-                        + message.hostEndPoint + ")");
+                        + hostEndpointId + ")");
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 4d302b1..27a78dd 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location.contexthub;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.PendingIntent;
@@ -27,13 +28,6 @@
 import android.database.ContentObserver;
 import android.hardware.SensorPrivacyManager;
 import android.hardware.SensorPrivacyManagerInternal;
-import android.hardware.contexthub.V1_0.AsyncEventType;
-import android.hardware.contexthub.V1_0.ContextHub;
-import android.hardware.contexthub.V1_0.ContextHubMsg;
-import android.hardware.contexthub.V1_0.Result;
-import android.hardware.contexthub.V1_0.TransactionResult;
-import android.hardware.contexthub.V1_2.HubAppInfo;
-import android.hardware.contexthub.V1_2.IContexthubCallback;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
 import android.hardware.location.ContextHubTransaction;
@@ -67,6 +61,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -97,6 +93,20 @@
 
     private static final int OS_APP_INSTANCE = -1;
 
+    /**
+     * Constants describing an async event from the Context Hub.
+     * {@hide}
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "CONTEXT_HUB_EVENT_" }, value = {
+            CONTEXT_HUB_EVENT_UNKNOWN,
+            CONTEXT_HUB_EVENT_RESTARTED,
+    })
+    public @interface Type { }
+
+    public static final int CONTEXT_HUB_EVENT_UNKNOWN = 0;
+    public static final int CONTEXT_HUB_EVENT_RESTARTED = 1;
+
     /*
      * Local flag to enable debug logging.
      */
@@ -136,7 +146,7 @@
     /**
      * Class extending the callback to register with a Context Hub.
      */
-    private class ContextHubServiceCallback extends IContexthubCallback.Stub {
+    private class ContextHubServiceCallback implements IContextHubWrapper.ICallback {
         private final int mContextHubId;
 
         ContextHubServiceCallback(int contextHubId) {
@@ -144,45 +154,31 @@
         }
 
         @Override
-        public void handleClientMsg(ContextHubMsg message) {
-            handleClientMessageCallback(mContextHubId, message,
-                    Collections.emptyList() /* nanoappPermissions */,
-                    Collections.emptyList() /* messagePermissions */);
+        public void handleTransactionResult(int transactionId, boolean success) {
+            handleTransactionResultCallback(mContextHubId, transactionId, success);
         }
 
         @Override
-        public void handleTxnResult(int transactionId, int result) {
-            handleTransactionResultCallback(mContextHubId, transactionId, result);
-        }
-
-        @Override
-        public void handleHubEvent(int eventType) {
+        public void handleContextHubEvent(int eventType) {
             handleHubEventCallback(mContextHubId, eventType);
         }
 
         @Override
-        public void handleAppAbort(long nanoAppId, int abortCode) {
-            handleAppAbortCallback(mContextHubId, nanoAppId, abortCode);
+        public void handleNanoappAbort(long nanoappId, int abortCode) {
+            handleAppAbortCallback(mContextHubId, nanoappId, abortCode);
         }
 
         @Override
-        public void handleAppsInfo(
-                ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> nanoAppInfoList) {
-            handleQueryAppsCallback(mContextHubId,
-                    ContextHubServiceUtil.toHubAppInfo_1_2(nanoAppInfoList));
+        public void handleNanoappInfo(List<NanoAppState> nanoappStateList) {
+            handleQueryAppsCallback(mContextHubId, nanoappStateList);
         }
 
         @Override
-        public void handleClientMsg_1_2(android.hardware.contexthub.V1_2.ContextHubMsg message,
-                ArrayList<String> messagePermissions) {
-            handleClientMessageCallback(mContextHubId, message.msg_1_0, message.permissions,
+        public void handleNanoappMessage(short hostEndpointId, NanoAppMessage message,
+                List<String> nanoappPermissions, List<String> messagePermissions) {
+            handleClientMessageCallback(mContextHubId, hostEndpointId, message, nanoappPermissions,
                     messagePermissions);
         }
-
-        @Override
-        public void handleAppsInfo_1_2(ArrayList<HubAppInfo> nanoAppInfoList) {
-            handleQueryAppsCallback(mContextHubId, nanoAppInfoList);
-        }
     }
 
     public ContextHubService(Context context) {
@@ -200,7 +196,7 @@
             return;
         }
 
-        Pair<List<ContextHub>, List<String>> hubInfo;
+        Pair<List<ContextHubInfo>, List<String>> hubInfo;
         try {
             hubInfo = mContextHubWrapper.getHubs();
         } catch (RemoteException e) {
@@ -214,7 +210,7 @@
         mContextHubInfoList = new ArrayList<>(mContextHubIdToInfoMap.values());
         mClientManager = new ContextHubClientManager(mContext, mContextHubWrapper);
         mTransactionManager = new ContextHubTransactionManager(
-                mContextHubWrapper.getHub(), mClientManager, mNanoAppStateManager);
+                mContextHubWrapper, mClientManager, mNanoAppStateManager);
         mSensorPrivacyManagerInternal =
                 LocalServices.getService(SensorPrivacyManagerInternal.class);
 
@@ -261,7 +257,7 @@
                 public void onReceive(Context context, Intent intent) {
                     if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())
                             || WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED.equals(
-                                intent.getAction())) {
+                            intent.getAction())) {
                         sendWifiSettingUpdate(false /* forceUpdate */);
                     }
                 }
@@ -304,7 +300,7 @@
                             Log.d(TAG, "User: " + userId + "mic privacy: " + enabled);
                             sendMicrophoneDisableSettingUpdate(enabled);
                         }
-                });
+                    });
 
         }
     }
@@ -329,7 +325,7 @@
 
             @Override
             public void onHubReset() {
-                byte[] data = {TransactionResult.SUCCESS};
+                byte[] data = {android.hardware.contexthub.V1_0.TransactionResult.SUCCESS};
                 onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
             }
 
@@ -560,17 +556,17 @@
 
     /**
      * Performs a query at the specified hub.
-     *
+     * <p>
      * This method should only be invoked internally by the service, either to update the service
      * cache or as a result of an explicit query requested by a client through the sendMessage API.
      *
      * @param contextHubId the ID of the hub to do the query
-     * @return the result of the query
+     * @return true if the query succeeded
      * @throws IllegalStateException if the transaction queue is full
      */
-    private int queryNanoAppsInternal(int contextHubId) {
+    private boolean queryNanoAppsInternal(int contextHubId) {
         if (mContextHubWrapper == null) {
-            return Result.UNKNOWN_FAILURE;
+            return false;
         }
 
         IContextHubTransactionCallback onCompleteCallback =
@@ -579,7 +575,7 @@
                 contextHubId, onCompleteCallback, getCallingPackageName());
 
         mTransactionManager.addTransaction(transaction);
-        return Result.OK;
+        return true;
     }
 
     @Override
@@ -605,7 +601,7 @@
         boolean success = false;
         if (nanoAppHandle == OS_APP_INSTANCE) {
             if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
-                success = (queryNanoAppsInternal(contextHubHandle) == Result.OK);
+                success = queryNanoAppsInternal(contextHubHandle);
             } else {
                 Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
             }
@@ -631,14 +627,16 @@
      * Handles a unicast or broadcast message from a nanoapp.
      *
      * @param contextHubId   the ID of the hub the message came from
+     * @param hostEndpointId the host endpoint ID of the client receiving this message
      * @param message        the message contents
      * @param reqPermissions the permissions required to consume this message
      */
     private void handleClientMessageCallback(
-            int contextHubId, ContextHubMsg message, List<String> nanoappPermissions,
+            int contextHubId, short hostEndpointId, NanoAppMessage message,
+            List<String> nanoappPermissions,
             List<String> messagePermissions) {
         mClientManager.onMessageFromNanoApp(
-                contextHubId, message, nanoappPermissions, messagePermissions);
+                contextHubId, hostEndpointId, message, nanoappPermissions, messagePermissions);
     }
 
     /**
@@ -663,7 +661,7 @@
 
     /**
      * A helper function to handle an unload response from the Context Hub for the old API.
-     *
+     * <p>
      * TODO(b/69270990): Remove this once the old APIs are obsolete.
      */
     private void handleUnloadResponseOldApi(int contextHubId, int result) {
@@ -677,20 +675,21 @@
      *
      * @param contextHubId  the ID of the hub the response came from
      * @param transactionId the ID of the transaction
-     * @param result        the result of the transaction reported by the hub
+     * @param success       true if the transaction succeeded
      */
-    private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) {
-        mTransactionManager.onTransactionResponse(transactionId, result);
+    private void handleTransactionResultCallback(int contextHubId, int transactionId,
+            boolean success) {
+        mTransactionManager.onTransactionResponse(transactionId, success);
     }
 
     /**
      * Handles an asynchronous event from a Context Hub.
      *
      * @param contextHubId the ID of the hub the response came from
-     * @param eventType    the type of the event as defined in Context Hub HAL AsyncEventType
+     * @param eventType    the type of the event as in CONTEXT_HUB_EVENT_*
      */
     private void handleHubEventCallback(int contextHubId, int eventType) {
-        if (eventType == AsyncEventType.RESTARTED) {
+        if (eventType == CONTEXT_HUB_EVENT_RESTARTED) {
             sendLocationSettingUpdate();
             sendWifiSettingUpdate(true /* forceUpdate */);
             sendAirplaneModeSettingUpdate();
@@ -720,15 +719,12 @@
     /**
      * Handles a query response from a Context Hub.
      *
-     * @param contextHubId    the ID of the hub of the response
-     * @param nanoAppInfoList the list of loaded nanoapps
+     * @param contextHubId     the ID of the hub of the response
+     * @param nanoappStateList the list of loaded nanoapps
      */
-    private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
-        List<NanoAppState> nanoAppStateList =
-                ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
-
-        mNanoAppStateManager.updateCache(contextHubId, nanoAppInfoList);
-        mTransactionManager.onQueryResponse(nanoAppStateList);
+    private void handleQueryAppsCallback(int contextHubId, List<NanoAppState> nanoappStateList) {
+        mNanoAppStateManager.updateCache(contextHubId, nanoappStateList);
+        mTransactionManager.onQueryResponse(nanoappStateList);
     }
 
     /**
@@ -771,9 +767,9 @@
     /**
      * Creates and registers a PendingIntent client at the service for the specified Context Hub.
      *
-     * @param contextHubId  the ID of the hub this client is attached to
-     * @param pendingIntent the PendingIntent associated with this client
-     * @param nanoAppId     the ID of the nanoapp PendingIntent events will be sent for
+     * @param contextHubId   the ID of the hub this client is attached to
+     * @param pendingIntent  the PendingIntent associated with this client
+     * @param nanoAppId      the ID of the nanoapp PendingIntent events will be sent for
      * @param attributionTag an optional attribution tag within the given package
      * @return the generated client interface
      * @throws IllegalArgumentException if hubInfo does not represent a valid hub
@@ -1093,8 +1089,8 @@
     }
 
     /**
-     * Obtains the latest microphone disabled setting for the current user
-     * and notifies the Context Hub.
+     * Obtains the latest microphone disabled setting for the current user and notifies the Context
+     * Hub.
      */
     private void sendMicrophoneDisableSettingUpdateForCurrentUser() {
         boolean isEnabled = mSensorPrivacyManagerInternal.isSensorPrivacyEnabled(
@@ -1121,9 +1117,9 @@
     }
 
     /**
-     * Send a microphone disable settings update whenever the foreground user changes.
-     * We always send a settings update regardless of the previous state for the same user
-     * since the CHRE framework is expected to handle repeated identical setting update.
+     * Send a microphone disable settings update whenever the foreground user changes. We always
+     * send a settings update regardless of the previous state for the same user since the CHRE
+     * framework is expected to handle repeated identical setting update.
      */
     public void onUserChanged() {
         Log.d(TAG, "User changed to id: " + getCurrentUserId());
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index 70f50c3..df6cc05 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -20,7 +20,7 @@
 
 import android.Manifest;
 import android.content.Context;
-import android.hardware.contexthub.V1_0.ContextHub;
+import android.hardware.contexthub.V1_0.AsyncEventType;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
 import android.hardware.contexthub.V1_0.HostEndPoint;
 import android.hardware.contexthub.V1_0.Result;
@@ -52,10 +52,10 @@
      * @return the HashMap object
      */
     /* package */
-    static HashMap<Integer, ContextHubInfo> createContextHubInfoMap(List<ContextHub> hubList) {
+    static HashMap<Integer, ContextHubInfo> createContextHubInfoMap(List<ContextHubInfo> hubList) {
         HashMap<Integer, ContextHubInfo> contextHubIdToInfoMap = new HashMap<>();
-        for (ContextHub contextHub : hubList) {
-            contextHubIdToInfoMap.put(contextHub.hubId, new ContextHubInfo(contextHub));
+        for (ContextHubInfo contextHubInfo : hubList) {
+            contextHubIdToInfoMap.put(contextHubInfo.getId(), contextHubInfo);
         }
 
         return contextHubIdToInfoMap;
@@ -257,4 +257,21 @@
         }
         return newAppInfo;
     }
+
+    /**
+     * Converts a HIDL AsyncEventType to the corresponding ContextHubService.CONTEXT_HUB_EVENT_*.
+     *
+     * @param hidlEventType The AsyncEventType value.
+     * @return The converted event type.
+     */
+    /* package */
+    static int toContextHubEvent(int hidlEventType) {
+        switch (hidlEventType) {
+            case AsyncEventType.RESTARTED:
+                return ContextHubService.CONTEXT_HUB_EVENT_RESTARTED;
+            default:
+                Log.e(TAG, "toContextHubEvent: Unknown event type: " + hidlEventType);
+                return ContextHubService.CONTEXT_HUB_EVENT_UNKNOWN;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index f81208f..abf5a24 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -16,9 +16,6 @@
 
 package com.android.server.location.contexthub;
 
-import android.hardware.contexthub.V1_0.IContexthub;
-import android.hardware.contexthub.V1_0.Result;
-import android.hardware.contexthub.V1_0.TransactionResult;
 import android.hardware.location.ContextHubTransaction;
 import android.hardware.location.IContextHubTransactionCallback;
 import android.hardware.location.NanoAppBinary;
@@ -40,7 +37,7 @@
 
 /**
  * Manages transactions at the Context Hub Service.
- *
+ * <p>
  * This class maintains a queue of transaction requests made to the ContextHubService by clients,
  * and executes them through the Context Hub. At any point in time, either the transaction queue is
  * empty, or there is a pending transaction that is waiting for an asynchronous response from the
@@ -64,7 +61,7 @@
     /*
      * The proxy to talk to the Context Hub
      */
-    private final IContexthub mContextHubProxy;
+    private final IContextHubWrapper mContextHubProxy;
 
     /*
      * The manager for all clients for the service.
@@ -120,7 +117,7 @@
     }
 
     /* package */ ContextHubTransactionManager(
-            IContexthub contextHubProxy, ContextHubClientManager clientManager,
+            IContextHubWrapper contextHubProxy, ContextHubClientManager clientManager,
             NanoAppStateManager nanoAppStateManager) {
         mContextHubProxy = contextHubProxy;
         mClientManager = clientManager;
@@ -143,15 +140,13 @@
                 nanoAppBinary.getNanoAppId(), packageName) {
             @Override
                 /* package */ int onTransact() {
-                android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary =
-                        ContextHubServiceUtil.createHidlNanoAppBinary(nanoAppBinary);
                 try {
-                    return mContextHubProxy.loadNanoApp(
-                            contextHubId, hidlNanoAppBinary, this.getTransactionId());
+                    return mContextHubProxy.loadNanoapp(
+                            contextHubId, nanoAppBinary, this.getTransactionId());
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException while trying to load nanoapp with ID 0x" +
                             Long.toHexString(nanoAppBinary.getNanoAppId()), e);
-                    return Result.UNKNOWN_FAILURE;
+                    return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
                 }
             }
 
@@ -194,12 +189,12 @@
             @Override
                 /* package */ int onTransact() {
                 try {
-                    return mContextHubProxy.unloadNanoApp(
+                    return mContextHubProxy.unloadNanoapp(
                             contextHubId, nanoAppId, this.getTransactionId());
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException while trying to unload nanoapp with ID 0x" +
                             Long.toHexString(nanoAppId), e);
-                    return Result.UNKNOWN_FAILURE;
+                    return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
                 }
             }
 
@@ -237,12 +232,12 @@
             @Override
                 /* package */ int onTransact() {
                 try {
-                    return mContextHubProxy.enableNanoApp(
+                    return mContextHubProxy.enableNanoapp(
                             contextHubId, nanoAppId, this.getTransactionId());
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException while trying to enable nanoapp with ID 0x" +
                             Long.toHexString(nanoAppId), e);
-                    return Result.UNKNOWN_FAILURE;
+                    return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
                 }
             }
 
@@ -274,12 +269,12 @@
             @Override
                 /* package */ int onTransact() {
                 try {
-                    return mContextHubProxy.disableNanoApp(
+                    return mContextHubProxy.disableNanoapp(
                             contextHubId, nanoAppId, this.getTransactionId());
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException while trying to disable nanoapp with ID 0x" +
                             Long.toHexString(nanoAppId), e);
-                    return Result.UNKNOWN_FAILURE;
+                    return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
                 }
             }
 
@@ -310,10 +305,10 @@
             @Override
                 /* package */ int onTransact() {
                 try {
-                    return mContextHubProxy.queryApps(contextHubId);
+                    return mContextHubProxy.queryNanoapps(contextHubId);
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException while trying to query for nanoapps", e);
-                    return Result.UNKNOWN_FAILURE;
+                    return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
                 }
             }
 
@@ -336,7 +331,7 @@
 
     /**
      * Adds a new transaction to the queue.
-     *
+     * <p>
      * If there was no pending transaction at the time, the transaction that was added will be
      * started in this method. If there were too many transactions in the queue, an exception will
      * be thrown.
@@ -363,10 +358,10 @@
      * Handles a transaction response from a Context Hub.
      *
      * @param transactionId the transaction ID of the response
-     * @param result        the result of the transaction as defined by the HAL TransactionResult
+     * @param success       true if the transaction succeeded
      */
     /* package */
-    synchronized void onTransactionResponse(int transactionId, int result) {
+    synchronized void onTransactionResponse(int transactionId, boolean success) {
         ContextHubServiceTransaction transaction = mTransactionQueue.peek();
         if (transaction == null) {
             Log.w(TAG, "Received unexpected transaction response (no transaction pending)");
@@ -378,9 +373,7 @@
             return;
         }
 
-        transaction.onTransactionComplete(
-                (result == TransactionResult.SUCCESS) ?
-                        ContextHubTransaction.RESULT_SUCCESS :
+        transaction.onTransactionComplete(success ? ContextHubTransaction.RESULT_SUCCESS :
                         ContextHubTransaction.RESULT_FAILED_AT_HUB);
         removeTransactionAndStartNext();
     }
@@ -421,11 +414,11 @@
 
     /**
      * Pops the front transaction from the queue and starts the next pending transaction request.
-     *
+     * <p>
      * Removing elements from the transaction queue must only be done through this method. When a
      * pending transaction is removed, the timeout timer is cancelled and the transaction is marked
      * complete.
-     *
+     * <p>
      * It is assumed that the transaction queue is non-empty when this method is invoked, and that
      * the caller has obtained a lock on this ContextHubTransactionManager object.
      */
@@ -442,21 +435,21 @@
 
     /**
      * Starts the next pending transaction request.
-     *
+     * <p>
      * Starting new transactions must only be done through this method. This method continues to
      * process the transaction queue as long as there are pending requests, and no transaction is
      * pending.
-     *
+     * <p>
      * It is assumed that the caller has obtained a lock on this ContextHubTransactionManager
      * object.
      */
     private void startNextTransaction() {
-        int result = Result.UNKNOWN_FAILURE;
-        while (result != Result.OK && !mTransactionQueue.isEmpty()) {
+        int result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+        while (result != ContextHubTransaction.RESULT_SUCCESS && !mTransactionQueue.isEmpty()) {
             ContextHubServiceTransaction transaction = mTransactionQueue.peek();
             result = transaction.onTransact();
 
-            if (result == Result.OK) {
+            if (result == ContextHubTransaction.RESULT_SUCCESS) {
                 Runnable onTimeoutFunc = () -> {
                     synchronized (this) {
                         if (!transaction.isComplete()) {
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 7be47a4..d733db0 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -15,11 +15,20 @@
  */
 package com.android.server.location.contexthub;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.hardware.contexthub.V1_0.ContextHub;
+import android.hardware.contexthub.V1_0.ContextHubMsg;
+import android.hardware.contexthub.V1_0.TransactionResult;
 import android.hardware.contexthub.V1_1.Setting;
 import android.hardware.contexthub.V1_1.SettingValue;
+import android.hardware.contexthub.V1_2.HubAppInfo;
 import android.hardware.contexthub.V1_2.IContexthubCallback;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppMessage;
+import android.hardware.location.NanoAppState;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Pair;
@@ -36,6 +45,45 @@
     private static final String TAG = "IContextHubWrapper";
 
     /**
+     * The callback interface to use in registerCallback.
+     */
+    public interface ICallback {
+        /**
+         * @param transactionId The ID of the transaction that completed.
+         * @param success       true if the transaction succeeded.
+         */
+        void handleTransactionResult(int transactionId, boolean success);
+
+        /**
+         * @param eventType The Context Hub event type defined by ContextHubService
+         *                  .CONTEXT_HUB_EVENT_*.
+         */
+        void handleContextHubEvent(int eventType);
+
+        /**
+         * @param nanoappId The ID of the nanoapp that aborted.
+         * @param abortCode The nanoapp-defined abort code.
+         */
+        void handleNanoappAbort(long nanoappId, int abortCode);
+
+        /**
+         * @param nanoappStateList The list of loaded nanoapps on the Context Hub.
+         */
+        void handleNanoappInfo(List<NanoAppState> nanoappStateList);
+
+        /**
+         * Handles a message from a nanoapp to a ContextHubClient.
+         *
+         * @param hostEndpointId     The host endpoint ID of the recipient.
+         * @param message            The message from the nanoapp.
+         * @param nanoappPermissions The list of permissions held by the nanoapp.
+         * @param messagePermissions The list of permissions required to receive the message.
+         */
+        void handleNanoappMessage(short hostEndpointId, NanoAppMessage message,
+                List<String> nanoappPermissions, List<String> messagePermissions);
+    }
+
+    /**
      * Attempts to connect to the Contexthub HAL 1.0 service, if it exists.
      *
      * @return A valid IContextHubWrapper if the connection was successful, null otherwise.
@@ -95,18 +143,7 @@
     /**
      * Calls the appropriate getHubs function depending on the HAL version.
      */
-    public abstract Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException;
-
-    /**
-     * Calls the appropriate registerCallback function depending on the HAL version.
-     */
-    public abstract void registerCallback(
-            int hubId, IContexthubCallback callback) throws RemoteException;
-
-    /**
-     * @return A valid instance of Contexthub HAL 1.0.
-     */
-    public abstract android.hardware.contexthub.V1_0.IContexthub getHub();
+    public abstract Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException;
 
     /**
      * @return True if this version of the Contexthub HAL supports Location setting notifications.
@@ -147,35 +184,211 @@
     public abstract void onAirplaneModeSettingChanged(boolean enabled);
 
     /**
-     * @return True if this version of the Contexthub HAL supports microphone
-     * disable setting notifications.
+     * @return True if this version of the Contexthub HAL supports microphone disable setting
+     * notifications.
      */
     public abstract boolean supportsMicrophoneDisableSettingNotifications();
 
     /**
-     * Notifies the Contexthub implementation of a microphone disable setting
-     * change.
+     * Notifies the Contexthub implementation of a microphone disable setting change.
      */
     public abstract void onMicrophoneDisableSettingChanged(boolean enabled);
 
-    private static class ContextHubWrapperV1_0 extends IContextHubWrapper {
+    /**
+     * Sends a message to the Context Hub.
+     *
+     * @param hostEndpointId The host endpoint ID of the sender.
+     * @param contextHubId   The ID of the Context Hub to send the message to.
+     * @param message        The message to send.
+     * @return the result of the message sending.
+     */
+    @ContextHubTransaction.Result
+    public abstract int sendMessageToContextHub(
+            short hostEndpointId, int contextHubId, NanoAppMessage message)
+            throws RemoteException;
+
+    /**
+     * Loads a nanoapp on the Context Hub.
+     *
+     * @param contextHubId  The ID of the Context Hub to load the nanoapp to.
+     * @param binary        The nanoapp binary to load.
+     * @param transactionId The transaction ID of this load.
+     * @return the result of this load transaction.
+     */
+    @ContextHubTransaction.Result
+    public abstract int loadNanoapp(int contextHubId, NanoAppBinary binary,
+            int transactionId) throws RemoteException;
+
+    /**
+     * Unloads a nanoapp on the Context Hub. Semantics are similar to loadNanoapp().
+     */
+    @ContextHubTransaction.Result
+    public abstract int unloadNanoapp(int contextHubId, long nanoappId,
+            int transactionId) throws RemoteException;
+
+    /**
+     * Enables a nanoapp on the Context Hub. Semantics are similar to loadNanoapp().
+     */
+    @ContextHubTransaction.Result
+    public abstract int enableNanoapp(int contextHubId, long nanoappId,
+            int transactionId) throws RemoteException;
+
+    /**
+     * Disables a nanoapp on the Context Hub. Semantics are similar to loadNanoapp().
+     */
+    @ContextHubTransaction.Result
+    public abstract int disableNanoapp(int contextHubId, long nanoappId,
+            int transactionId) throws RemoteException;
+
+    /**
+     * Queries a list of nanoapp from the Context hub.
+     *
+     * @param contextHubId The ID of the Context Hub to query.
+     * @return the result of this query transaction.
+     */
+    @ContextHubTransaction.Result
+    public abstract int queryNanoapps(int contextHubId) throws RemoteException;
+
+    /**
+     * Registers a callback with the Context Hub.
+     *
+     * @param contextHubId The ID of the Context Hub to register the callback with.
+     * @param callback     The callback to register.
+     */
+    public abstract void registerCallback(int contextHubId, @NonNull ICallback callback)
+            throws RemoteException;
+
+    /**
+     * An abstract call that defines methods common to all HIDL IContextHubWrappers.
+     */
+    private abstract static class ContextHubWrapperHidl extends IContextHubWrapper {
         private android.hardware.contexthub.V1_0.IContexthub mHub;
 
-        ContextHubWrapperV1_0(android.hardware.contexthub.V1_0.IContexthub hub) {
+        protected ICallback mCallback = null;
+
+        protected final ContextHubWrapperHidlCallback mHidlCallback =
+                new ContextHubWrapperHidlCallback();
+
+        protected class ContextHubWrapperHidlCallback extends IContexthubCallback.Stub {
+            @Override
+            public void handleClientMsg(ContextHubMsg message) {
+                mCallback.handleNanoappMessage(
+                        message.hostEndPoint,
+                        ContextHubServiceUtil.createNanoAppMessage(message),
+                        Collections.emptyList() /* nanoappPermissions */,
+                        Collections.emptyList() /* messagePermissions */);
+            }
+
+            @Override
+            public void handleTxnResult(int transactionId, int result) {
+                mCallback.handleTransactionResult(transactionId,
+                        result == TransactionResult.SUCCESS);
+            }
+
+            @Override
+            public void handleHubEvent(int eventType) {
+                mCallback.handleContextHubEvent(
+                        ContextHubServiceUtil.toContextHubEvent(eventType));
+            }
+
+            @Override
+            public void handleAppAbort(long nanoAppId, int abortCode) {
+                mCallback.handleNanoappAbort(nanoAppId, abortCode);
+            }
+
+            @Override
+            public void handleAppsInfo(
+                    ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> nanoAppInfoList) {
+                handleAppsInfo_1_2(ContextHubServiceUtil.toHubAppInfo_1_2(nanoAppInfoList));
+            }
+
+            @Override
+            public void handleClientMsg_1_2(android.hardware.contexthub.V1_2.ContextHubMsg message,
+                    ArrayList<String> messagePermissions) {
+                mCallback.handleNanoappMessage(
+                        message.msg_1_0.hostEndPoint,
+                        ContextHubServiceUtil.createNanoAppMessage(message.msg_1_0),
+                        message.permissions, messagePermissions);
+            }
+
+            @Override
+            public void handleAppsInfo_1_2(ArrayList<HubAppInfo> nanoAppInfoList) {
+                List<NanoAppState> nanoAppStateList =
+                        ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
+                mCallback.handleNanoappInfo(nanoAppStateList);
+            }
+        }
+
+        ContextHubWrapperHidl(android.hardware.contexthub.V1_0.IContexthub hub) {
             mHub = hub;
         }
 
-        public Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException {
-            return new Pair(mHub.getHubs(), new ArrayList<String>());
+        @ContextHubTransaction.Result
+        public int sendMessageToContextHub(
+                short hostEndpointId, int contextHubId, NanoAppMessage message)
+                throws RemoteException {
+            ContextHubMsg messageToNanoApp =
+                    ContextHubServiceUtil.createHidlContextHubMessage(hostEndpointId, message);
+            return ContextHubServiceUtil.toTransactionResult(
+                    mHub.sendMessageToHub(contextHubId, messageToNanoApp));
         }
 
-        public void registerCallback(
-                int hubId, IContexthubCallback callback) throws RemoteException {
-            mHub.registerCallback(hubId, callback);
+        @ContextHubTransaction.Result
+        public int loadNanoapp(int contextHubId, NanoAppBinary binary,
+                int transactionId) throws RemoteException {
+            android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary =
+                    ContextHubServiceUtil.createHidlNanoAppBinary(binary);
+            return ContextHubServiceUtil.toTransactionResult(mHub.loadNanoApp(
+                    contextHubId, hidlNanoAppBinary, transactionId));
         }
 
-        public android.hardware.contexthub.V1_0.IContexthub getHub() {
-            return mHub;
+        @ContextHubTransaction.Result
+        public int unloadNanoapp(int contextHubId, long nanoappId, int transactionId)
+                throws RemoteException {
+            return ContextHubServiceUtil.toTransactionResult(mHub.unloadNanoApp(
+                    contextHubId, nanoappId, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int enableNanoapp(int contextHubId, long nanoappId, int transactionId)
+                throws RemoteException {
+            return ContextHubServiceUtil.toTransactionResult(mHub.enableNanoApp(
+                    contextHubId, nanoappId, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int disableNanoapp(int contextHubId, long nanoappId, int transactionId)
+                throws RemoteException {
+            return ContextHubServiceUtil.toTransactionResult(mHub.disableNanoApp(
+                    contextHubId, nanoappId, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int queryNanoapps(int contextHubId) throws RemoteException {
+            return ContextHubServiceUtil.toTransactionResult(
+                    mHub.queryApps(contextHubId));
+        }
+
+        public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
+            mCallback = callback;
+            mHub.registerCallback(contextHubId, mHidlCallback);
+        }
+    }
+
+    private static class ContextHubWrapperV1_0 extends ContextHubWrapperHidl {
+        private android.hardware.contexthub.V1_0.IContexthub mHub;
+
+        ContextHubWrapperV1_0(android.hardware.contexthub.V1_0.IContexthub hub) {
+            super(hub);
+            mHub = hub;
+        }
+
+        public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
+            ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
+            for (ContextHub hub : mHub.getHubs()) {
+                hubInfoList.add(new ContextHubInfo(hub));
+            }
+            return new Pair(hubInfoList, new ArrayList<String>());
         }
 
         public boolean supportsLocationSettingNotifications() {
@@ -207,24 +420,20 @@
         }
     }
 
-    private static class ContextHubWrapperV1_1 extends IContextHubWrapper {
+    private static class ContextHubWrapperV1_1 extends ContextHubWrapperHidl {
         private android.hardware.contexthub.V1_1.IContexthub mHub;
 
         ContextHubWrapperV1_1(android.hardware.contexthub.V1_1.IContexthub hub) {
+            super(hub);
             mHub = hub;
         }
 
-        public Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException {
-            return new Pair(mHub.getHubs(), new ArrayList<String>());
-        }
-
-        public void registerCallback(
-                int hubId, IContexthubCallback callback) throws RemoteException {
-            mHub.registerCallback(hubId, callback);
-        }
-
-        public android.hardware.contexthub.V1_0.IContexthub getHub() {
-            return mHub;
+        public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
+            ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
+            for (ContextHub hub : mHub.getHubs()) {
+                hubInfoList.add(new ContextHubInfo(hub));
+            }
+            return new Pair(hubInfoList, new ArrayList<String>());
         }
 
         public boolean supportsLocationSettingNotifications() {
@@ -262,36 +471,32 @@
         }
     }
 
-    private static class ContextHubWrapperV1_2 extends IContextHubWrapper
+    private static class ContextHubWrapperV1_2 extends ContextHubWrapperHidl
             implements android.hardware.contexthub.V1_2.IContexthub.getHubs_1_2Callback {
         private final android.hardware.contexthub.V1_2.IContexthub mHub;
 
-        private Pair<List<ContextHub>, List<String>> mHubInfo =
+        private Pair<List<ContextHubInfo>, List<String>> mHubInfo =
                 new Pair<>(Collections.emptyList(), Collections.emptyList());
 
         ContextHubWrapperV1_2(android.hardware.contexthub.V1_2.IContexthub hub) {
+            super(hub);
             mHub = hub;
         }
 
         @Override
         public void onValues(ArrayList<ContextHub> hubs, ArrayList<String> supportedPermissions) {
-            mHubInfo = new Pair(hubs, supportedPermissions);
+            ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
+            for (ContextHub hub : hubs) {
+                hubInfoList.add(new ContextHubInfo(hub));
+            }
+            mHubInfo = new Pair(hubInfoList, supportedPermissions);
         }
 
-        public Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException {
+        public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
             mHub.getHubs_1_2(this);
             return mHubInfo;
         }
 
-        public void registerCallback(
-                int hubId, IContexthubCallback callback) throws RemoteException {
-            mHub.registerCallback_1_2(hubId, callback);
-        }
-
-        public android.hardware.contexthub.V1_0.IContexthub getHub() {
-            return mHub;
-        }
-
         public boolean supportsLocationSettingNotifications() {
             return true;
         }
@@ -331,6 +536,11 @@
                     enabled ? SettingValue.DISABLED : SettingValue.ENABLED);
         }
 
+        public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
+            mCallback = callback;
+            mHub.registerCallback_1_2(contextHubId, mHidlCallback);
+        }
+
         private void sendSettingChanged(byte setting, byte newValue) {
             try {
                 mHub.onSettingChanged_1_2(setting, newValue);
diff --git a/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java b/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
index 667fb98..b6d5496 100644
--- a/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
+++ b/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
@@ -17,8 +17,8 @@
 package com.android.server.location.contexthub;
 
 import android.annotation.Nullable;
-import android.hardware.contexthub.V1_2.HubAppInfo;
 import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppState;
 import android.util.Log;
 
 import java.util.HashMap;
@@ -31,8 +31,8 @@
  * Manages the state of loaded nanoapps at the Context Hubs.
  *
  * This class maintains a list of nanoapps that have been informed as loaded at the hubs. The state
- * should be updated based on the hub callbacks (defined in IContexthubCallback.hal), as a result
- * of either loadNanoApp, unloadNanoApp, or queryApps.
+ * should be updated based on the hub callbacks (defined in IContexthubCallback.hal), as a result of
+ * either loadNanoApp, unloadNanoApp, or queryApps.
  *
  * The state tracked by this manager is used by clients of ContextHubService that use the old APIs.
  *
@@ -61,7 +61,7 @@
     /**
      * @param nanoAppHandle the nanoapp handle
      * @return the NanoAppInstanceInfo for the given nanoapp, or null if the nanoapp does not exist
-     *         in the cache
+     * in the cache
      */
     @Nullable
     /* package */
@@ -83,7 +83,7 @@
 
     /**
      * @param contextHubId the ID of the hub to search for the instance
-     * @param nanoAppId the unique 64-bit ID of the nanoapp
+     * @param nanoAppId    the unique 64-bit ID of the nanoapp
      * @return the nanoapp handle, -1 if the nanoapp is not in the cache
      */
     /* package */
@@ -99,12 +99,12 @@
 
     /**
      * Adds a nanoapp instance to the cache.
-     *
+     * <p>
      * If the cache already contained the nanoapp, the entry is removed and a new nanoapp handle is
      * generated.
      *
-     * @param contextHubId the ID of the hub the nanoapp is loaded in
-     * @param nanoAppId the unique 64-bit ID of the nanoapp
+     * @param contextHubId   the ID of the hub the nanoapp is loaded in
+     * @param nanoAppId      the unique 64-bit ID of the nanoapp
      * @param nanoAppVersion the version of the nanoapp
      */
     /* package */
@@ -147,15 +147,17 @@
     /**
      * Performs a batch update of the nanoapp cache given a nanoapp query response.
      *
-     * @param contextHubId    the ID of the hub the response came from
-     * @param nanoAppInfoList the list of loaded nanoapps
+     * @param contextHubId     the ID of the hub the response came from
+     * @param nanoappStateList the list of loaded nanoapps
      */
     /* package */
-    synchronized void updateCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
+    synchronized void updateCache(int contextHubId, List<NanoAppState> nanoappStateList) {
         HashSet<Long> nanoAppIdSet = new HashSet<>();
-        for (HubAppInfo appInfo : nanoAppInfoList) {
-            handleQueryAppEntry(contextHubId, appInfo.info_1_0.appId, appInfo.info_1_0.version);
-            nanoAppIdSet.add(appInfo.info_1_0.appId);
+        for (NanoAppState nanoappState : nanoappStateList) {
+            handleQueryAppEntry(
+                    contextHubId, nanoappState.getNanoAppId(),
+                    (int) nanoappState.getNanoAppVersion());
+            nanoAppIdSet.add(nanoappState.getNanoAppId());
         }
 
         Iterator<NanoAppInstanceInfo> iterator = mNanoAppHash.values().iterator();
@@ -172,8 +174,8 @@
      * If the nanoapp exists in the cache, then the entry is updated. Otherwise, inserts a new
      * instance of the nanoapp in the cache. This method should only be invoked from updateCache.
      *
-     * @param contextHubId the ID of the hub the nanoapp is loaded in
-     * @param nanoAppId the unique 64-bit ID of the nanoapp
+     * @param contextHubId   the ID of the hub the nanoapp is loaded in
+     * @param nanoAppId      the unique 64-bit ID of the nanoapp
      * @param nanoAppVersion the version of the nanoapp
      */
     private void handleQueryAppEntry(int contextHubId, long nanoAppId, int nanoAppVersion) {
diff --git a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
index 12dd3e6..47146c1 100644
--- a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
@@ -16,217 +16,193 @@
 
 package com.android.server.location.eventlog;
 
-import android.annotation.Nullable;
-import android.os.SystemClock;
-import android.util.TimeUtils;
+import static java.lang.Integer.bitCount;
 
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
-import java.util.Iterator;
+import java.lang.reflect.Array;
+import java.util.Arrays;
 import java.util.NoSuchElementException;
-import java.util.function.Consumer;
+import java.util.Objects;
 
 /**
- * An in-memory event log to support historical event information.
+ * An in-memory event log to support historical event information. The log is of a constant size,
+ * and new events will overwrite old events as the log fills up.
+ *
+ * @param <T> log event type
  */
-public abstract class LocalEventLog {
-
-    private interface Log {
-        // true if this is a filler element that should not be queried
-        boolean isFiller();
-        long getTimeDeltaMs();
-        String getLogString();
-        boolean filter(@Nullable String filter);
-    }
-
-    private static final class FillerEvent implements Log {
-
-        static final long MAX_TIME_DELTA = (1L << 32) - 1;
-
-        private final int mTimeDelta;
-
-        FillerEvent(long timeDelta) {
-            Preconditions.checkArgument(timeDelta >= 0);
-            mTimeDelta = (int) timeDelta;
-        }
-
-        @Override
-        public boolean isFiller() {
-            return true;
-        }
-
-        @Override
-        public long getTimeDeltaMs() {
-            return Integer.toUnsignedLong(mTimeDelta);
-        }
-
-        @Override
-        public String getLogString() {
-            throw new AssertionError();
-        }
-
-        @Override
-        public boolean filter(String filter) {
-            return false;
-        }
-    }
+public class LocalEventLog<T> {
 
     /**
-     * An abstraction of a log event to be implemented by subclasses.
+     * Consumer of log events for iterating over the log.
+     *
+     * @param <T> log event type
      */
-    public abstract static class LogEvent implements Log {
-
-        static final long MAX_TIME_DELTA = (1L << 32) - 1;
-
-        private final int mTimeDelta;
-
-        protected LogEvent(long timeDelta) {
-            Preconditions.checkArgument(timeDelta >= 0);
-            mTimeDelta = (int) timeDelta;
-        }
-
-        @Override
-        public final boolean isFiller() {
-            return false;
-        }
-
-        @Override
-        public final long getTimeDeltaMs() {
-            return Integer.toUnsignedLong(mTimeDelta);
-        }
-
-        @Override
-        public boolean filter(String filter) {
-            return false;
-        }
+    public interface LogConsumer<T> {
+        /** Invoked with a time and a logEvent. */
+        void acceptLog(long time, T logEvent);
     }
 
-    // circular buffer of log entries
-    private final Log[] mLog;
-    private int mLogSize;
-    private int mLogEndIndex;
+    // masks for the entries field. 1 bit is used to indicate whether this is a filler event or not,
+    // and 31 bits to store the time delta.
+    private static final int IS_FILLER_MASK = 0b10000000000000000000000000000000;
+    private static final int TIME_DELTA_MASK = 0b01111111111111111111111111111111;
+
+    private static final int IS_FILLER_OFFSET = countTrailingZeros(IS_FILLER_MASK);
+    private static final int TIME_DELTA_OFFSET = countTrailingZeros(TIME_DELTA_MASK);
+
+    static final int MAX_TIME_DELTA = (1 << bitCount(TIME_DELTA_MASK)) - 1;
+
+    private static int countTrailingZeros(int i) {
+        int c = 0;
+        while (i != 0 && (i & 1) == 0) {
+            c++;
+            i = i >>> 1;
+        }
+        return c;
+    }
+
+    private static int createEntry(boolean isFiller, int timeDelta) {
+        Preconditions.checkArgument(timeDelta >= 0 && timeDelta <= MAX_TIME_DELTA);
+        return (((isFiller ? 1 : 0) << IS_FILLER_OFFSET) & IS_FILLER_MASK)
+                | ((timeDelta << TIME_DELTA_OFFSET) & TIME_DELTA_MASK);
+    }
+
+    static int getTimeDelta(int entry) {
+        return (entry & TIME_DELTA_MASK) >>> TIME_DELTA_OFFSET;
+    }
+
+    static boolean isFiller(int entry) {
+        return (entry & IS_FILLER_MASK) != 0;
+    }
+
+    // circular buffer of log entries and events. each entry corrosponds to the log event at the
+    // same index. the log entry holds the filler status and time delta according to the bit masks
+    // above, and the log event is the log event.
+
+    @GuardedBy("this")
+    final int[] mEntries;
+
+    @GuardedBy("this")
+    final @Nullable T[] mLogEvents;
+
+    @GuardedBy("this")
+    int mLogSize;
+
+    @GuardedBy("this")
+    int mLogEndIndex;
 
     // invalid if log is empty
-    private long mStartRealtimeMs;
-    private long mLastLogRealtimeMs;
 
-    public LocalEventLog(int size) {
+    @GuardedBy("this")
+    long mStartTime;
+
+    @GuardedBy("this")
+    long mLastLogTime;
+
+    @SuppressWarnings("unchecked")
+    public LocalEventLog(int size, Class<T> clazz) {
         Preconditions.checkArgument(size > 0);
-        mLog = new Log[size];
+
+        mEntries = new int[size];
+        mLogEvents = (T[]) Array.newInstance(clazz, size);
         mLogSize = 0;
         mLogEndIndex = 0;
 
-        mStartRealtimeMs = -1;
-        mLastLogRealtimeMs = -1;
+        mStartTime = -1;
+        mLastLogTime = -1;
     }
 
-    /**
-     * Should be overridden by subclasses to return a new immutable log event for the given
-     * arguments (as passed into {@link #addLogEvent(int, Object...)}.
-     */
-    protected abstract LogEvent createLogEvent(long timeDelta, int event, Object... args);
-
-    /**
-     * May be optionally overridden by subclasses if they wish to change how log event time is
-     * formatted.
-     */
-    protected String getTimePrefix(long timeMs) {
-        return TimeUtils.logTimeOfDay(timeMs) + ": ";
-    }
-
-    /**
-     * Call to add a new log event at the current time. The arguments provided here will be passed
-     * into {@link #createLogEvent(long, int, Object...)} in addition to a time delta, and should be
-     * used to construct an appropriate {@link LogEvent} object.
-     */
-    public synchronized void addLogEvent(int event, Object... args) {
-        long timeMs = SystemClock.elapsedRealtime();
+    /** Call to add a new log event at the given time. */
+    protected synchronized void addLog(long time, T logEvent) {
+        Preconditions.checkArgument(logEvent != null);
 
         // calculate delta
         long delta = 0;
         if (!isEmpty()) {
-            delta = timeMs - mLastLogRealtimeMs;
+            delta = time - mLastLogTime;
 
-            // if the delta is invalid, or if the delta is great enough using filler elements would
+            // if the delta is negative, or if the delta is great enough using filler elements would
             // result in an empty log anyways, just clear the log and continue, otherwise insert
             // filler elements until we have a reasonable delta
-            if (delta < 0 || (delta / FillerEvent.MAX_TIME_DELTA) >= mLog.length - 1) {
+            if (delta < 0 || (delta / MAX_TIME_DELTA) >= mEntries.length - 1) {
                 clear();
                 delta = 0;
             } else {
-                while (delta >= LogEvent.MAX_TIME_DELTA) {
-                    long timeDelta = Math.min(FillerEvent.MAX_TIME_DELTA, delta);
-                    addLogEventInternal(new FillerEvent(timeDelta));
-                    delta -= timeDelta;
+                while (delta >= MAX_TIME_DELTA) {
+                    addLogEventInternal(true, MAX_TIME_DELTA, null);
+                    delta -= MAX_TIME_DELTA;
                 }
             }
         }
 
         // for first log entry, set initial times
         if (isEmpty()) {
-            mStartRealtimeMs = timeMs;
-            mLastLogRealtimeMs = mStartRealtimeMs;
+            mStartTime = time;
+            mLastLogTime = mStartTime;
         }
 
-        addLogEventInternal(createLogEvent(delta, event, args));
+        addLogEventInternal(false, (int) delta, logEvent);
     }
 
-    private void addLogEventInternal(Log event) {
-        Preconditions.checkState(mStartRealtimeMs != -1 && mLastLogRealtimeMs != -1);
+    @GuardedBy("this")
+    private void addLogEventInternal(boolean isFiller, int timeDelta, @Nullable T logEvent) {
+        Preconditions.checkArgument(isFiller || logEvent != null);
+        Preconditions.checkState(mStartTime != -1 && mLastLogTime != -1);
 
-        if (mLogSize == mLog.length) {
+        if (mLogSize == mEntries.length) {
             // if log is full, size will remain the same, but update the start time
-            mStartRealtimeMs += mLog[startIndex()].getTimeDeltaMs();
+            mStartTime += getTimeDelta(mEntries[startIndex()]);
         } else {
             // otherwise add an item
             mLogSize++;
         }
 
         // set log and increment end index
-        mLog[mLogEndIndex] = event;
+        mEntries[mLogEndIndex] = createEntry(isFiller, timeDelta);
+        mLogEvents[mLogEndIndex] = logEvent;
         mLogEndIndex = incrementIndex(mLogEndIndex);
-        mLastLogRealtimeMs = mLastLogRealtimeMs + event.getTimeDeltaMs();
+        mLastLogTime = mLastLogTime + timeDelta;
     }
 
     /** Clears the log of all entries. */
     public synchronized void clear() {
+        // clear entries to allow gc
+        Arrays.fill(mLogEvents, null);
+
         mLogEndIndex = 0;
         mLogSize = 0;
 
-        mStartRealtimeMs = -1;
-        mLastLogRealtimeMs = -1;
+        mStartTime = -1;
+        mLastLogTime = -1;
     }
 
     // checks if the log is empty (if empty, times are invalid)
-    private synchronized boolean isEmpty() {
+    @GuardedBy("this")
+    private boolean isEmpty() {
         return mLogSize == 0;
     }
 
     /** Iterates over the event log, passing each log string to the given consumer. */
-    public synchronized void iterate(Consumer<String> consumer) {
+    public synchronized void iterate(LogConsumer<? super T> consumer) {
         LogIterator it = new LogIterator();
         while (it.hasNext()) {
-            consumer.accept(it.next());
-        }
-    }
-
-    /**
-     * Iterates over the event log, passing each filter-matching log string to the given
-     * consumer.
-     */
-    public synchronized void iterate(String filter, Consumer<String> consumer) {
-        LogIterator it = new LogIterator(filter);
-        while (it.hasNext()) {
-            consumer.accept(it.next());
+            it.next();
+            consumer.acceptLog(it.getTime(), it.getLog());
         }
     }
 
     // returns the index of the first element
+    @GuardedBy("this")
     private int startIndex() {
         return wrapIndex(mLogEndIndex - mLogSize);
     }
 
     // returns the index after this one
+    @GuardedBy("this")
     private int incrementIndex(int index) {
         if (index == -1) {
             return startIndex();
@@ -238,69 +214,68 @@
     }
 
     // rolls over the given index if necessary
+    @GuardedBy("this")
     private int wrapIndex(int index) {
         // java modulo will keep negative sign, we need to rollover
-        return (index % mLog.length + mLog.length) % mLog.length;
+        return (index % mEntries.length + mEntries.length) % mEntries.length;
     }
 
-    private class LogIterator implements Iterator<String> {
+    private class LogIterator {
 
-        private final @Nullable String mFilter;
-
-        private final long mSystemTimeDeltaMs;
-
-        private long mCurrentRealtimeMs;
+        private long mLogTime;
         private int mIndex;
         private int mCount;
 
+        private long mCurrentTime;
+        private T mCurrentLogEvent;
+
         LogIterator() {
-            this(null);
-        }
+            synchronized (LocalEventLog.this) {
+                mLogTime = mStartTime;
+                mIndex = -1;
+                mCount = -1;
 
-        LogIterator(@Nullable String filter) {
-            mFilter = filter;
-            mSystemTimeDeltaMs = System.currentTimeMillis() - SystemClock.elapsedRealtime();
-            mCurrentRealtimeMs = mStartRealtimeMs;
-            mIndex = -1;
-            mCount = -1;
-
-            increment();
-        }
-
-        @Override
-        public boolean hasNext() {
-            return mCount < mLogSize;
-        }
-
-        public String next() {
-            if (!hasNext()) {
-                throw new NoSuchElementException();
+                increment();
             }
-
-            Log log = mLog[mIndex];
-            long timeMs = mCurrentRealtimeMs + log.getTimeDeltaMs() + mSystemTimeDeltaMs;
-
-            increment();
-
-            return getTimePrefix(timeMs) + log.getLogString();
         }
 
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
+        public boolean hasNext() {
+            synchronized (LocalEventLog.this) {
+                return mCount < mLogSize;
+            }
         }
 
-        private void increment() {
-            long nextDeltaMs = mIndex == -1 ? 0 : mLog[mIndex].getTimeDeltaMs();
+        public void next() {
+            synchronized (LocalEventLog.this) {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                mCurrentTime = mLogTime + getTimeDelta(mEntries[mIndex]);
+                mCurrentLogEvent = Objects.requireNonNull(mLogEvents[mIndex]);
+
+                increment();
+            }
+        }
+
+        public long getTime() {
+            return mCurrentTime;
+        }
+
+        public T getLog() {
+            return mCurrentLogEvent;
+        }
+
+        @GuardedBy("LocalEventLog.this")
+        private void increment(LogIterator this) {
+            long nextDeltaMs = mIndex == -1 ? 0 : getTimeDelta(mEntries[mIndex]);
             do {
-                mCurrentRealtimeMs += nextDeltaMs;
+                mLogTime += nextDeltaMs;
                 mIndex = incrementIndex(mIndex);
                 if (++mCount < mLogSize) {
-                    nextDeltaMs = mLog[mIndex].getTimeDeltaMs();
+                    nextDeltaMs = getTimeDelta(mEntries[mIndex]);
                 }
-            } while (mCount < mLogSize && (mLog[mIndex].isFiller() || (mFilter != null
-                    && !mLog[mIndex].filter(mFilter))));
+            } while (mCount < mLogSize && isFiller(mEntries[mIndex]));
         }
     }
 }
-
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index db2a43f..94953e0 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -36,12 +36,15 @@
 import android.os.PowerManager.LocationPowerSaveMode;
 import android.os.SystemClock;
 import android.util.ArrayMap;
+import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
+import java.util.function.Consumer;
+
 /** In memory event log for location events. */
-public class LocationEventLog extends LocalEventLog {
+public class LocationEventLog extends LocalEventLog<Object> {
 
     public static final LocationEventLog EVENT_LOG = new LocationEventLog();
 
@@ -53,28 +56,11 @@
         }
     }
 
-    private static final int EVENT_USER_SWITCHED = 1;
-    private static final int EVENT_LOCATION_ENABLED = 2;
-    private static final int EVENT_ADAS_LOCATION_ENABLED = 3;
-    private static final int EVENT_PROVIDER_ENABLED = 4;
-    private static final int EVENT_PROVIDER_MOCKED = 5;
-    private static final int EVENT_PROVIDER_CLIENT_REGISTER = 6;
-    private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 7;
-    private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 8;
-    private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 9;
-    private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 10;
-    private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 11;
-    private static final int EVENT_PROVIDER_UPDATE_REQUEST = 12;
-    private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 13;
-    private static final int EVENT_PROVIDER_DELIVER_LOCATION = 14;
-    private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 15;
-    private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 16;
-
     @GuardedBy("mAggregateStats")
     private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
 
     public LocationEventLog() {
-        super(getLogSize());
+        super(getLogSize(), Object.class);
         mAggregateStats = new ArrayMap<>(4);
     }
 
@@ -109,39 +95,39 @@
 
     /** Logs a user switched event. */
     public void logUserSwitched(int userIdFrom, int userIdTo) {
-        addLogEvent(EVENT_USER_SWITCHED, userIdFrom, userIdTo);
+        addLogEvent(new UserSwitchedEvent(userIdFrom, userIdTo));
     }
 
     /** Logs a location enabled/disabled event. */
     public void logLocationEnabled(int userId, boolean enabled) {
-        addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled);
+        addLogEvent(new LocationEnabledEvent(userId, enabled));
     }
 
     /** Logs a location enabled/disabled event. */
     public void logAdasLocationEnabled(int userId, boolean enabled) {
-        addLogEvent(EVENT_ADAS_LOCATION_ENABLED, userId, enabled);
+        addLogEvent(new LocationAdasEnabledEvent(userId, enabled));
     }
 
     /** Logs a location provider enabled/disabled event. */
     public void logProviderEnabled(String provider, int userId, boolean enabled) {
-        addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled);
+        addLogEvent(new ProviderEnabledEvent(provider, userId, enabled));
     }
 
     /** Logs a location provider being replaced/unreplaced by a mock provider. */
     public void logProviderMocked(String provider, boolean mocked) {
-        addLogEvent(EVENT_PROVIDER_MOCKED, provider, mocked);
+        addLogEvent(new ProviderMockedEvent(provider, mocked));
     }
 
     /** Logs a new client registration for a location provider. */
     public void logProviderClientRegistered(String provider, CallerIdentity identity,
             LocationRequest request) {
-        addLogEvent(EVENT_PROVIDER_CLIENT_REGISTER, provider, identity, request);
+        addLogEvent(new ProviderClientRegisterEvent(provider, true, identity, request));
         getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis());
     }
 
     /** Logs a client unregistration for a location provider. */
     public void logProviderClientUnregistered(String provider, CallerIdentity identity) {
-        addLogEvent(EVENT_PROVIDER_CLIENT_UNREGISTER, provider, identity);
+        addLogEvent(new ProviderClientRegisterEvent(provider, false, identity, null));
         getAggregateStats(provider, identity).markRequestRemoved();
     }
 
@@ -158,7 +144,7 @@
     /** Logs a client for a location provider entering the foreground state. */
     public void logProviderClientForeground(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(EVENT_PROVIDER_CLIENT_FOREGROUND, provider, identity);
+            addLogEvent(new ProviderClientForegroundEvent(provider, true, identity));
         }
         getAggregateStats(provider, identity).markRequestForeground();
     }
@@ -166,7 +152,7 @@
     /** Logs a client for a location provider leaving the foreground state. */
     public void logProviderClientBackground(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(EVENT_PROVIDER_CLIENT_BACKGROUND, provider, identity);
+            addLogEvent(new ProviderClientForegroundEvent(provider, false, identity));
         }
         getAggregateStats(provider, identity).markRequestBackground();
     }
@@ -174,34 +160,32 @@
     /** Logs a client for a location provider entering the permitted state. */
     public void logProviderClientPermitted(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(EVENT_PROVIDER_CLIENT_PERMITTED, provider, identity);
+            addLogEvent(new ProviderClientPermittedEvent(provider, true, identity));
         }
     }
 
     /** Logs a client for a location provider leaving the permitted state. */
     public void logProviderClientUnpermitted(String provider, CallerIdentity identity) {
         if (D) {
-            addLogEvent(EVENT_PROVIDER_CLIENT_UNPERMITTED, provider, identity);
+            addLogEvent(new ProviderClientPermittedEvent(provider, false, identity));
         }
     }
 
     /** Logs a change to the provider request for a location provider. */
     public void logProviderUpdateRequest(String provider, ProviderRequest request) {
-        addLogEvent(EVENT_PROVIDER_UPDATE_REQUEST, provider, request);
+        addLogEvent(new ProviderUpdateEvent(provider, request));
     }
 
     /** Logs a new incoming location for a location provider. */
     public void logProviderReceivedLocations(String provider, int numLocations) {
-        if (D) {
-            addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider, numLocations);
-        }
+        addLogEvent(new ProviderReceiveLocationEvent(provider, numLocations));
     }
 
     /** Logs a location deliver for a client of a location provider. */
     public void logProviderDeliveredLocations(String provider, int numLocations,
             CallerIdentity identity) {
         if (D) {
-            addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, numLocations, identity);
+            addLogEvent(new ProviderDeliverLocationEvent(provider, numLocations, identity));
         }
         getAggregateStats(provider, identity).markLocationDelivered();
     }
@@ -209,80 +193,47 @@
     /** Logs that a provider has entered or exited stationary throttling. */
     public void logProviderStationaryThrottled(String provider, boolean throttled,
             ProviderRequest request) {
-        addLogEvent(EVENT_PROVIDER_STATIONARY_THROTTLED, provider, throttled, request);
+        addLogEvent(new ProviderStationaryThrottledEvent(provider, throttled, request));
     }
 
     /** Logs that the location power save mode has changed. */
     public void logLocationPowerSaveMode(
             @LocationPowerSaveMode int locationPowerSaveMode) {
-        addLogEvent(EVENT_LOCATION_POWER_SAVE_MODE_CHANGE, locationPowerSaveMode);
+        addLogEvent(new LocationPowerSaveModeEvent(locationPowerSaveMode));
     }
 
-    @Override
-    protected LogEvent createLogEvent(long timeDelta, int event, Object... args) {
-        switch (event) {
-            case EVENT_USER_SWITCHED:
-                return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]);
-            case EVENT_LOCATION_ENABLED:
-                return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]);
-            case EVENT_ADAS_LOCATION_ENABLED:
-                return new LocationAdasEnabledEvent(timeDelta, (Integer) args[0],
-                        (Boolean) args[1]);
-            case EVENT_PROVIDER_ENABLED:
-                return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
-                        (Boolean) args[2]);
-            case EVENT_PROVIDER_MOCKED:
-                return new ProviderMockedEvent(timeDelta, (String) args[0], (Boolean) args[1]);
-            case EVENT_PROVIDER_CLIENT_REGISTER:
-                return new ProviderClientRegisterEvent(timeDelta, (String) args[0], true,
-                        (CallerIdentity) args[1], (LocationRequest) args[2]);
-            case EVENT_PROVIDER_CLIENT_UNREGISTER:
-                return new ProviderClientRegisterEvent(timeDelta, (String) args[0], false,
-                        (CallerIdentity) args[1], null);
-            case EVENT_PROVIDER_CLIENT_FOREGROUND:
-                return new ProviderClientForegroundEvent(timeDelta, (String) args[0], true,
-                        (CallerIdentity) args[1]);
-            case EVENT_PROVIDER_CLIENT_BACKGROUND:
-                return new ProviderClientForegroundEvent(timeDelta, (String) args[0], false,
-                        (CallerIdentity) args[1]);
-            case EVENT_PROVIDER_CLIENT_PERMITTED:
-                return new ProviderClientPermittedEvent(timeDelta, (String) args[0], true,
-                        (CallerIdentity) args[1]);
-            case EVENT_PROVIDER_CLIENT_UNPERMITTED:
-                return new ProviderClientPermittedEvent(timeDelta, (String) args[0], false,
-                        (CallerIdentity) args[1]);
-            case EVENT_PROVIDER_UPDATE_REQUEST:
-                return new ProviderUpdateEvent(timeDelta, (String) args[0],
-                        (ProviderRequest) args[1]);
-            case EVENT_PROVIDER_RECEIVE_LOCATION:
-                return new ProviderReceiveLocationEvent(timeDelta, (String) args[0],
-                        (Integer) args[1]);
-            case EVENT_PROVIDER_DELIVER_LOCATION:
-                return new ProviderDeliverLocationEvent(timeDelta, (String) args[0],
-                        (Integer) args[1], (CallerIdentity) args[2]);
-            case EVENT_PROVIDER_STATIONARY_THROTTLED:
-                return new ProviderStationaryThrottledEvent(timeDelta, (String) args[0],
-                        (Boolean) args[1], (ProviderRequest) args[2]);
-            case EVENT_LOCATION_POWER_SAVE_MODE_CHANGE:
-                return new LocationPowerSaveModeEvent(timeDelta, (Integer) args[0]);
-            default:
-                throw new AssertionError();
-        }
+    private void addLogEvent(Object logEvent) {
+        addLog(SystemClock.elapsedRealtime(), logEvent);
     }
 
-    private abstract static class ProviderEvent extends LogEvent {
+    public void iterate(Consumer<String> consumer) {
+        iterate(consumer, null);
+    }
+
+    public void iterate(Consumer<String> consumer, @Nullable String providerFilter) {
+        long systemTimeDeltaMs = System.currentTimeMillis() - SystemClock.elapsedRealtime();
+        StringBuilder builder = new StringBuilder();
+        iterate(
+                (time, logEvent) -> {
+                    boolean match = providerFilter == null || (logEvent instanceof ProviderEvent
+                            && providerFilter.equals(((ProviderEvent) logEvent).mProvider));
+                    if (match) {
+                        builder.setLength(0);
+                        builder.append(TimeUtils.logTimeOfDay(time + systemTimeDeltaMs));
+                        builder.append(": ");
+                        builder.append(logEvent);
+                        consumer.accept(builder.toString());
+                    }
+                });
+    }
+
+    private abstract static class ProviderEvent {
 
         protected final String mProvider;
 
-        ProviderEvent(long timeDelta, String provider) {
-            super(timeDelta);
+        ProviderEvent(String provider) {
             mProvider = provider;
         }
-
-        @Override
-        public boolean filter(String filter) {
-            return mProvider.equals(filter);
-        }
     }
 
     private static final class ProviderEnabledEvent extends ProviderEvent {
@@ -290,15 +241,15 @@
         private final int mUserId;
         private final boolean mEnabled;
 
-        ProviderEnabledEvent(long timeDelta, String provider, int userId,
+        ProviderEnabledEvent(String provider, int userId,
                 boolean enabled) {
-            super(timeDelta, provider);
+            super(provider);
             mUserId = userId;
             mEnabled = enabled;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider [u" + mUserId + "] " + (mEnabled ? "enabled"
                     : "disabled");
         }
@@ -308,13 +259,13 @@
 
         private final boolean mMocked;
 
-        ProviderMockedEvent(long timeDelta, String provider, boolean mocked) {
-            super(timeDelta, provider);
+        ProviderMockedEvent(String provider, boolean mocked) {
+            super(provider);
             mMocked = mocked;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             if (mMocked) {
                 return mProvider + " provider added mock provider override";
             } else {
@@ -329,16 +280,16 @@
         private final CallerIdentity mIdentity;
         @Nullable private final LocationRequest mLocationRequest;
 
-        ProviderClientRegisterEvent(long timeDelta, String provider, boolean registered,
+        ProviderClientRegisterEvent(String provider, boolean registered,
                 CallerIdentity identity, @Nullable LocationRequest locationRequest) {
-            super(timeDelta, provider);
+            super(provider);
             mRegistered = registered;
             mIdentity = identity;
             mLocationRequest = locationRequest;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             if (mRegistered) {
                 return mProvider + " provider +registration " + mIdentity + " -> "
                         + mLocationRequest;
@@ -353,15 +304,15 @@
         private final boolean mForeground;
         private final CallerIdentity mIdentity;
 
-        ProviderClientForegroundEvent(long timeDelta, String provider, boolean foreground,
+        ProviderClientForegroundEvent(String provider, boolean foreground,
                 CallerIdentity identity) {
-            super(timeDelta, provider);
+            super(provider);
             mForeground = foreground;
             mIdentity = identity;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider client " + mIdentity + " -> "
                     + (mForeground ? "foreground" : "background");
         }
@@ -372,15 +323,14 @@
         private final boolean mPermitted;
         private final CallerIdentity mIdentity;
 
-        ProviderClientPermittedEvent(long timeDelta, String provider, boolean permitted,
-                CallerIdentity identity) {
-            super(timeDelta, provider);
+        ProviderClientPermittedEvent(String provider, boolean permitted, CallerIdentity identity) {
+            super(provider);
             mPermitted = permitted;
             mIdentity = identity;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider client " + mIdentity + " -> "
                     + (mPermitted ? "permitted" : "unpermitted");
         }
@@ -390,13 +340,13 @@
 
         private final ProviderRequest mRequest;
 
-        ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) {
-            super(timeDelta, provider);
+        ProviderUpdateEvent(String provider, ProviderRequest request) {
+            super(provider);
             mRequest = request;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider request = " + mRequest;
         }
     }
@@ -405,13 +355,13 @@
 
         private final int mNumLocations;
 
-        ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
-            super(timeDelta, provider);
+        ProviderReceiveLocationEvent(String provider, int numLocations) {
+            super(provider);
             mNumLocations = numLocations;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider received location[" + mNumLocations + "]";
         }
     }
@@ -421,15 +371,15 @@
         private final int mNumLocations;
         @Nullable private final CallerIdentity mIdentity;
 
-        ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
+        ProviderDeliverLocationEvent(String provider, int numLocations,
                 @Nullable CallerIdentity identity) {
-            super(timeDelta, provider);
+            super(provider);
             mNumLocations = numLocations;
             mIdentity = identity;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider delivered location[" + mNumLocations + "] to "
                     + mIdentity;
         }
@@ -440,33 +390,31 @@
         private final boolean mStationaryThrottled;
         private final ProviderRequest mRequest;
 
-        ProviderStationaryThrottledEvent(long timeDelta, String provider,
-                boolean stationaryThrottled, ProviderRequest request) {
-            super(timeDelta, provider);
+        ProviderStationaryThrottledEvent(String provider, boolean stationaryThrottled,
+                ProviderRequest request) {
+            super(provider);
             mStationaryThrottled = stationaryThrottled;
             mRequest = request;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return mProvider + " provider stationary/idle " + (mStationaryThrottled ? "throttled"
                     : "unthrottled") + ", request = " + mRequest;
         }
     }
 
-    private static final class LocationPowerSaveModeEvent extends LogEvent {
+    private static final class LocationPowerSaveModeEvent {
 
         @LocationPowerSaveMode
         private final int mLocationPowerSaveMode;
 
-        LocationPowerSaveModeEvent(long timeDelta,
-                @LocationPowerSaveMode int locationPowerSaveMode) {
-            super(timeDelta);
+        LocationPowerSaveModeEvent(@LocationPowerSaveMode int locationPowerSaveMode) {
             mLocationPowerSaveMode = locationPowerSaveMode;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             String mode;
             switch (mLocationPowerSaveMode) {
                 case LOCATION_MODE_NO_CHANGE:
@@ -492,53 +440,50 @@
         }
     }
 
-    private static final class UserSwitchedEvent extends LogEvent {
+    private static final class UserSwitchedEvent {
 
         private final int mUserIdFrom;
         private final int mUserIdTo;
 
-        UserSwitchedEvent(long timeDelta, int userIdFrom, int userIdTo) {
-            super(timeDelta);
+        UserSwitchedEvent(int userIdFrom, int userIdTo) {
             mUserIdFrom = userIdFrom;
             mUserIdTo = userIdTo;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return "current user switched from u" + mUserIdFrom + " to u" + mUserIdTo;
         }
     }
 
-    private static final class LocationEnabledEvent extends LogEvent {
+    private static final class LocationEnabledEvent {
 
         private final int mUserId;
         private final boolean mEnabled;
 
-        LocationEnabledEvent(long timeDelta, int userId, boolean enabled) {
-            super(timeDelta);
+        LocationEnabledEvent(int userId, boolean enabled) {
             mUserId = userId;
             mEnabled = enabled;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return "location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled");
         }
     }
 
-    private static final class LocationAdasEnabledEvent extends LogEvent {
+    private static final class LocationAdasEnabledEvent {
 
         private final int mUserId;
         private final boolean mEnabled;
 
-        LocationAdasEnabledEvent(long timeDelta, int userId, boolean enabled) {
-            super(timeDelta);
+        LocationAdasEnabledEvent(int userId, boolean enabled) {
             mUserId = userId;
             mEnabled = enabled;
         }
 
         @Override
-        public String getLogString() {
+        public String toString() {
             return "adas location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled");
         }
     }
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 8955c28..62d8c32 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1078,7 +1078,7 @@
         }
 
         private void onTransportFailure(Exception e) {
-            if (e instanceof RemoteException) {
+            if (e instanceof PendingIntent.CanceledException) {
                 Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
                 synchronized (mLock) {
                     remove();
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 87982cd..65a3ad0 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -471,7 +471,9 @@
             for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
                 SessionsListenerRecord listener = mSessionsListeners.get(i);
                 try {
-                    enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
+                    String packageName = listener.componentName == null ? null :
+                            listener.componentName.getPackageName();
+                    enforceMediaPermissions(packageName, listener.pid, listener.uid,
                             listener.userId);
                 } catch (SecurityException e) {
                     Log.i(TAG, "ActiveSessionsListener " + listener.componentName
@@ -593,15 +595,13 @@
      * for the caller's user</li>
      * </ul>
      */
-    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
+    private void enforceMediaPermissions(String packageName, int pid, int uid,
             int resolvedUserId) {
         if (hasStatusBarServicePermission(pid, uid)) return;
-        // TODO: Refactor to use hasMediaControlPermission and hasEnabledNotificationListener
-        if (mContext
-                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
-                != PackageManager.PERMISSION_GRANTED
-                && !isEnabledNotificationListener(compName,
-                UserHandle.getUserHandleForUid(uid), resolvedUserId)) {
+        if (hasMediaControlPermission(pid, uid)) return;
+
+        if (packageName == null || !hasEnabledNotificationListener(
+                packageName, UserHandle.getUserHandleForUid(uid), resolvedUserId)) {
             throw new SecurityException("Missing permission to control media.");
         }
     }
@@ -632,29 +632,26 @@
     }
 
     /**
-     * This checks if the component is an enabled notification listener for the
+     * This checks if the given package has an enabled notification listener for the
      * specified user. Enabled components may only operate on behalf of the user
      * they're running as.
      *
-     * @param compName The component that is enabled.
+     * @param packageName The package name.
      * @param userHandle The user handle of the caller.
      * @param forUserId The user id they're making the request on behalf of.
-     * @return True if the component is enabled, false otherwise
+     * @return True if the app has an enabled notification listener for the user, false otherwise
      */
-    private boolean isEnabledNotificationListener(ComponentName compName, UserHandle userHandle,
-            int forUserId) {
+    private boolean hasEnabledNotificationListener(String packageName,
+            UserHandle userHandle, int forUserId) {
         if (userHandle.getIdentifier() != forUserId) {
             // You may not access another user's content as an enabled listener.
             return false;
         }
         if (DEBUG) {
-            Log.d(TAG, "Checking if enabled notification listener " + compName);
+            Log.d(TAG, "Checking whether the package " + packageName + " has an"
+                    + " enabled notification listener.");
         }
-        if (compName != null) {
-            return mNotificationManager.hasEnabledNotificationListener(compName.getPackageName(),
-                    userHandle);
-        }
-        return false;
+        return mNotificationManager.hasEnabledNotificationListener(packageName, userHandle);
     }
 
     /*
@@ -1237,16 +1234,16 @@
         }
 
         @Override
-        public MediaSession.Token getMediaKeyEventSession() {
+        public MediaSession.Token getMediaKeyEventSession(final String packageName) {
             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");
-                }
+                enforcePackageName(packageName, uid);
+                enforceMediaPermissions(packageName, pid, uid, userId);
+
                 MediaSessionRecordImpl record;
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
@@ -1268,16 +1265,16 @@
         }
 
         @Override
-        public String getMediaKeyEventSessionPackageName() {
+        public String getMediaKeyEventSessionPackageName(final String packageName) {
             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");
-                }
+                enforcePackageName(packageName, uid);
+                enforceMediaPermissions(packageName, pid, uid, userId);
+
                 MediaSessionRecordImpl record;
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
@@ -1588,20 +1585,22 @@
 
         @Override
         public void addOnMediaKeyEventSessionChangedListener(
-                final IOnMediaKeyEventSessionChangedListener listener) {
+                final IOnMediaKeyEventSessionChangedListener listener,
+                final String packageName) {
             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");
-                }
+                enforcePackageName(packageName, uid);
+                enforceMediaPermissions(packageName, pid, uid, userId);
+
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
                     if (user == null || user.mFullUserId != userId) {
@@ -1611,7 +1610,7 @@
                     }
                     user.addOnMediaKeyEventSessionChangedListenerLocked(listener, uid);
                     Log.d(TAG, "The MediaKeyEventSessionChangedListener (" + listener.asBinder()
-                            + ") is added by " + getCallingPackageName(uid));
+                            + ") is added by " + packageName);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1622,18 +1621,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) {
@@ -2116,7 +2113,7 @@
             int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
             // Check if they have the permissions or their component is enabled for the user
             // they're calling from.
-            enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+            enforceMediaPermissions(packageName, pid, uid, resolvedUserId);
             return resolvedUserId;
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 557fa89..df372b1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -290,7 +290,8 @@
                 combined.getValues(augmentStart, augmentEnd, entry);
             }
 
-            final long rawBytes = entry.rxBytes + entry.txBytes;
+            final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 :
+                    (entry.rxBytes + entry.txBytes);
             final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes;
             final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes;
             final long targetBytes = augmentPlan.getDataUsageBytes();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5ffb754..bd2a407 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7451,15 +7451,21 @@
                         sentAccessibilityEvent = true;
                     }
                     if (DBG) Slog.v(TAG, "Interrupting!");
+                    boolean isInsistentUpdate = isInsistentUpdate(record);
                     if (hasValidSound) {
-                        if (isInCall()) {
-                            playInCallNotification();
+                        if (isInsistentUpdate) {
+                            // don't reset insistent sound, it's jarring
                             beep = true;
                         } else {
-                            beep = playSound(record, soundUri);
-                        }
-                        if(beep) {
-                            mSoundNotificationKey = key;
+                            if (isInCall()) {
+                                playInCallNotification();
+                                beep = true;
+                            } else {
+                                beep = playSound(record, soundUri);
+                            }
+                            if (beep) {
+                                mSoundNotificationKey = key;
+                            }
                         }
                     }
 
@@ -7467,9 +7473,13 @@
                             mAudioManager.getRingerModeInternal()
                                     == AudioManager.RINGER_MODE_SILENT;
                     if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
-                        buzz = playVibration(record, vibration, hasValidSound);
-                        if(buzz) {
-                            mVibrateNotificationKey = key;
+                        if (isInsistentUpdate) {
+                            buzz = true;
+                        } else {
+                            buzz = playVibration(record, vibration, hasValidSound);
+                            if (buzz) {
+                                mVibrateNotificationKey = key;
+                            }
                         }
                     }
                 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
@@ -7573,6 +7583,19 @@
     }
 
     @GuardedBy("mNotificationLock")
+    boolean isInsistentUpdate(final NotificationRecord record) {
+        return (Objects.equals(record.getKey(), mSoundNotificationKey)
+                || Objects.equals(record.getKey(), mVibrateNotificationKey))
+                && isCurrentlyInsistent();
+    }
+
+    @GuardedBy("mNotificationLock")
+    boolean isCurrentlyInsistent() {
+        return isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey))
+                || isLoopingRingtoneNotification(mNotificationsByKey.get(mVibrateNotificationKey));
+    }
+
+    @GuardedBy("mNotificationLock")
     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
         // Suppressed because it's a silent update
         final Notification notification = record.getNotification();
@@ -7611,10 +7634,8 @@
             return true;
         }
 
-        // A looping ringtone, such as an incoming call is playing
-        if (isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey))
-                || isLoopingRingtoneNotification(
-                        mNotificationsByKey.get(mVibrateNotificationKey))) {
+        // A different looping ringtone, such as an incoming call is playing
+        if (isCurrentlyInsistent() && !isInsistentUpdate(record)) {
             return true;
         }
 
@@ -8758,10 +8779,22 @@
 
     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
             ManagedServiceInfo listener) {
-        String listenerName = listener == null ? null : listener.component.toShortString();
+        if (listener == null) {
+            return;
+        }
+        String listenerName = listener.component.toShortString();
         if ((duration <= 0 && snoozeCriterionId == null) || key == null) {
             return;
         }
+        synchronized (mNotificationLock) {
+            final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key);
+            if (r == null) {
+                return;
+            }
+            if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){
+                return;
+            }
+        }
 
         if (DBG) {
             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 7112ae1..628a322 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -22,6 +22,7 @@
 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.app.NotificationManager.INTERRUPTION_FILTER_UNKNOWN;
 
+import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.INotificationManager;
 import android.app.Notification;
@@ -44,6 +45,8 @@
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -392,19 +395,28 @@
                                     + "--context <snooze-criterion-id>) <key>");
                             return 1;
                     }
-                    if (null == mDirectService.getNotificationRecord(key)) {
-                        pw.println("error: no notification matching key: " + key);
-                        return 1;
-                    }
                     if (duration > 0 || criterion != null) {
+                        ShellNls nls = new ShellNls();
+                        nls.registerAsSystemService(mDirectService.getContext(),
+                                new ComponentName(nls.getClass().getPackageName(),
+                                        nls.getClass().getName()),
+                                ActivityManager.getCurrentUser());
+                        if (!waitForBind(nls)) {
+                            pw.println("error: could not bind a listener in time");
+                            return 1;
+                        }
                         if (duration > 0) {
                             pw.println(String.format("snoozing <%s> until time: %s", key,
                                     new Date(System.currentTimeMillis() + duration)));
+                            nls.snoozeNotification(key, duration);
                         } else {
                             pw.println(String.format("snoozing <%s> until criterion: %s", key,
                                     criterion));
+                            nls.snoozeNotification(key, criterion);
                         }
-                        mDirectService.snoozeNotificationInt(key, duration, criterion, null);
+                        waitForSnooze(nls, key);
+                        nls.unregisterAsSystemService();
+                        waitForUnbind(nls);
                     } else {
                         pw.println("error: invalid value for --" + subflag + ": " + flagarg);
                         return 1;
@@ -527,14 +539,17 @@
                     final PendingIntent pi;
                     if ("broadcast".equals(intentKind)) {
                         pi = PendingIntent.getBroadcastAsUser(
-                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED,
+                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+                                        | PendingIntent.FLAG_MUTABLE_UNAUDITED,
                                 UserHandle.CURRENT);
                     } else if ("service".equals(intentKind)) {
                         pi = PendingIntent.getService(
-                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+                                        | PendingIntent.FLAG_MUTABLE_UNAUDITED);
                     } else {
                         pi = PendingIntent.getActivityAsUser(
-                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED, null,
+                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+                                        | PendingIntent.FLAG_MUTABLE_UNAUDITED, null,
                                 UserHandle.CURRENT);
                     }
                     builder.setContentIntent(pi);
@@ -685,9 +700,79 @@
         return 0;
     }
 
+    private void waitForSnooze(ShellNls nls, String key) {
+        for (int i = 0; i < 20; i++) {
+            StatusBarNotification[] sbns = nls.getSnoozedNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                if (sbn.getKey().equals(key)) {
+                    return;
+                }
+            }
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        return;
+    }
+
+    private boolean waitForBind(ShellNls nls) {
+        for (int i = 0; i < 20; i++) {
+            if (nls.isConnected) {
+                Slog.i(TAG, "Bound Shell NLS");
+                return true;
+            } else {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return false;
+    }
+
+    private void waitForUnbind(ShellNls nls) {
+        for (int i = 0; i < 10; i++) {
+            if (!nls.isConnected) {
+                Slog.i(TAG, "Unbound Shell NLS");
+                return;
+            } else {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
     @Override
     public void onHelp() {
         getOutPrintWriter().println(USAGE);
     }
+
+    @SuppressLint("OverrideAbstract")
+    private static class ShellNls extends NotificationListenerService {
+        private static ShellNls
+                sNotificationListenerInstance = null;
+        boolean isConnected;
+
+        @Override
+        public void onListenerConnected() {
+            super.onListenerConnected();
+            sNotificationListenerInstance = this;
+            isConnected = true;
+        }
+        @Override
+        public void onListenerDisconnected() {
+            isConnected = false;
+        }
+
+        public static ShellNls getInstance() {
+            return sNotificationListenerInstance;
+        }
+    }
 }
 
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 96bde3d..e8a3a81 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -330,8 +330,7 @@
                                             }
                                         }
 
-                                        if (isShortcutOk(channel) && isDeletionOk(channel)
-                                                && !channel.isSoundMissing()) {
+                                        if (isShortcutOk(channel) && isDeletionOk(channel)) {
                                             r.channels.put(id, channel);
                                         }
                                     }
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 157a1fc..903d02a 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -229,7 +229,7 @@
 
     private boolean matchesActorSignature(@NonNull AndroidPackage targetPackage,
             @NonNull AndroidPackage overlayPackage, int userId) {
-        String targetOverlayableName = overlayPackage.getOverlayTargetName();
+        String targetOverlayableName = overlayPackage.getOverlayTargetOverlayableName();
         if (targetOverlayableName != null) {
             try {
                 OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget(
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index e4ca5b6..ae683d4 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -100,7 +100,8 @@
         if (!Objects.equals(theTruth.getOverlayTarget(), oldSettings.targetPackageName)) {
             return true;
         }
-        if (!Objects.equals(theTruth.getOverlayTargetName(), oldSettings.targetOverlayableName)) {
+        if (!Objects.equals(theTruth.getOverlayTargetOverlayableName(),
+                oldSettings.targetOverlayableName)) {
             return true;
         }
         if (oldSettings.isFabricated) {
@@ -343,7 +344,7 @@
                 }
 
                 currentInfo = mSettings.init(overlay, userId, pkg.getOverlayTarget(),
-                        pkg.getOverlayTargetName(), pkg.getBaseApkPath(),
+                        pkg.getOverlayTargetOverlayableName(), pkg.getBaseApkPath(),
                         isPackageConfiguredMutable(pkg),
                         isPackageConfiguredEnabled(pkg),
                         getPackageConfiguredPriority(pkg), pkg.getOverlayCategory(),
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index 94a1f3b..539fecf 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -129,7 +129,7 @@
                     return Collections.emptyMap();
                 }
 
-                String overlayable = pkg.getOverlayTargetName();
+                String overlayable = pkg.getOverlayTargetOverlayableName();
                 Map<String, Set<String>> targetToOverlayables = new HashMap<>();
                 Set<String> overlayables = new HashSet<>();
                 overlayables.add(overlayable);
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
index 947405e..b276c6f 100644
--- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -19,10 +19,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Build;
 import android.os.IDeviceIdentifiersPolicyService;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.server.SystemService;
@@ -65,11 +68,31 @@
         @Override
         public @Nullable String getSerialForPackage(String callingPackage,
                 String callingFeatureId) throws RemoteException {
+            if (!checkPackageBelongsToCaller(callingPackage)) {
+                throw new IllegalArgumentException(
+                        "Invalid callingPackage or callingPackage does not belong to caller's uid:"
+                                + Binder.getCallingUid());
+            }
+
             if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
                     callingPackage, callingFeatureId, "getSerial")) {
                 return Build.UNKNOWN;
             }
             return SystemProperties.get("ro.serialno", Build.UNKNOWN);
         }
+
+        private boolean checkPackageBelongsToCaller(String callingPackage) {
+            int callingUid = Binder.getCallingUid();
+            int callingUserId = UserHandle.getUserId(callingUid);
+            int callingPackageUid;
+            try {
+                callingPackageUid = mContext.getPackageManager().getPackageUidAsUser(
+                        callingPackage, callingUserId);
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+
+            return callingPackageUid == callingUid;
+        }
     }
 }
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/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index a44cad8..aa467e7 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -64,7 +64,6 @@
 import com.android.internal.security.VerityUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
-import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -724,16 +723,20 @@
         }
     }
 
+    static final int MIN_BUFFER_SIZE = 4 * 1024;
+    static final int MAX_BUFFER_SIZE = 128 * 1024;
+
     private static byte[] getApkChecksum(File file, int type) {
-        try (FileInputStream fis = new FileInputStream(file);
-             BufferedInputStream bis = new BufferedInputStream(fis)) {
-            byte[] dataBytes = new byte[512 * 1024];
+        final int bufferSize = (int) Math.max(MIN_BUFFER_SIZE,
+                Math.min(MAX_BUFFER_SIZE, file.length()));
+        try (FileInputStream fis = new FileInputStream(file)) {
+            final byte[] buffer = new byte[bufferSize];
             int nread = 0;
 
             final String algo = getMessageDigestAlgoForChecksumKind(type);
             MessageDigest md = MessageDigest.getInstance(algo);
-            while ((nread = bis.read(dataBytes)) != -1) {
-                md.update(dataBytes, 0, nread);
+            while ((nread = fis.read(buffer)) != -1) {
+                md.update(buffer, 0, nread);
             }
 
             return md.digest();
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 56b77b5..3818d74 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -57,6 +57,7 @@
 import com.android.server.compat.CompatChange;
 import com.android.server.om.OverlayReferenceMapper;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
 import com.android.server.utils.Snapshots;
@@ -97,6 +98,13 @@
     private final SparseSetArray<Integer> mImplicitlyQueryable = new SparseSetArray<>();
 
     /**
+     * This contains a list of app UIDs that are implicitly queryable because another app explicitly
+     * interacted with it, but could keep across package updates. For example, if application A
+     * grants persistable uri permission to application B; regardless of any manifest entries.
+     */
+    private final SparseSetArray<Integer> mRetainedImplicitlyQueryable = new SparseSetArray<>();
+
+    /**
      * A mapping from the set of App IDs that query other App IDs via package name to the
      * list of packages that they can see.
      */
@@ -256,6 +264,7 @@
      */
     private AppsFilter(AppsFilter orig) {
         Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
+        Snapshots.copy(mRetainedImplicitlyQueryable, orig.mRetainedImplicitlyQueryable);
         Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
         Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
         Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
@@ -440,7 +449,8 @@
             // TODO(b/135203078): Do not use toAppInfo
             // TODO(b/167551701): Make changeId non-logging
             final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternalNoLogging(
-                    PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
+                    PackageManager.FILTER_APPLICATION_QUERY,
+                    AndroidPackageUtils.generateAppInfoWithoutState(pkg));
             if (enabled) {
                 mDisabledPackages.remove(pkg.getPackageName());
             } else {
@@ -633,15 +643,19 @@
      *
      * @param recipientUid the uid gaining visibility of the {@code visibleUid}.
      * @param visibleUid   the uid becoming visible to the {@recipientUid}
+     * @param retainOnUpdate  if the implicit access retained across package updates.
      * @return {@code true} if implicit access was not already granted.
      */
-    public boolean grantImplicitAccess(int recipientUid, int visibleUid) {
+    public boolean grantImplicitAccess(int recipientUid, int visibleUid, boolean retainOnUpdate) {
         if (recipientUid == visibleUid) {
             return false;
         }
-        final boolean changed = mImplicitlyQueryable.add(recipientUid, visibleUid);
+        final boolean changed = retainOnUpdate
+                ? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
+                : mImplicitlyQueryable.add(recipientUid, visibleUid);
         if (changed && DEBUG_LOGGING) {
-            Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+            Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: "
+                    + recipientUid + " -> " + visibleUid);
         }
         synchronized (mCacheLock) {
             if (mShouldFilterCache != null) {
@@ -677,7 +691,7 @@
         try {
             if (isReplace) {
                 // let's first remove any prior rules for this package
-                removePackage(newPkgSetting);
+                removePackage(newPkgSetting, true /*isReplace*/);
             }
             mStateProvider.runWithState((settings, users) -> {
                 ArraySet<String> additionalChangedPackages =
@@ -1078,8 +1092,9 @@
      * Removes a package for consideration when filtering visibility between apps.
      *
      * @param setting the setting of the package being removed.
+     * @param isReplace if the package is being replaced.
      */
-    public void removePackage(PackageSetting setting) {
+    public void removePackage(PackageSetting setting, boolean isReplace) {
         mStateProvider.runWithState((settings, users) -> {
             final int userCount = users.length;
             for (int u = 0; u < userCount; u++) {
@@ -1089,6 +1104,16 @@
                 for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
                     mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
                 }
+
+                if (isReplace) {
+                    continue;
+                }
+
+                mRetainedImplicitlyQueryable.remove(removingUid);
+                for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
+                    mRetainedImplicitlyQueryable.remove(
+                            mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+                }
             }
 
             if (!mQueriesViaComponentRequireRecompute) {
@@ -1414,6 +1439,24 @@
 
             try {
                 if (DEBUG_TRACING) {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mRetainedImplicitlyQueryable");
+                }
+                final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
+                if (mRetainedImplicitlyQueryable.contains(callingUid, targetUid)) {
+                    if (DEBUG_LOGGING) {
+                        log(callingSetting, targetPkgSetting,
+                                "retained implicitly queryable for user");
+                    }
+                    return false;
+                }
+            } finally {
+                if (DEBUG_TRACING) {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+            }
+
+            try {
+                if (DEBUG_TRACING) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
                 }
                 final String targetName = targetPkg.getPackageName();
@@ -1542,7 +1585,7 @@
         dumpPackageSet(pw, filteringAppId, mForceQueryable, "forceQueryable", "  ", expandPackages);
         pw.println("  queries via package name:");
         dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, "    ", expandPackages);
-        pw.println("  queries via intent:");
+        pw.println("  queries via component:");
         dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, "    ", expandPackages);
         pw.println("  queryable via interaction:");
         for (int user : users) {
@@ -1550,6 +1593,9 @@
             dumpQueriesMap(pw,
                     filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
                     mImplicitlyQueryable, "      ", expandPackages);
+            dumpQueriesMap(pw,
+                    filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
+                    mRetainedImplicitlyQueryable, "      ", expandPackages);
         }
         pw.println("  queryable via uses-library:");
         dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, "    ", expandPackages);
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index dde9f82..e0f11e2 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -59,6 +59,7 @@
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.PackageInfoUtils.CachedApplicationInfoGenerator;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
 import com.android.server.utils.WatchableImpl;
@@ -684,7 +685,8 @@
             AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
 
             if (pkg != null) {
-                pw.print("      applicationInfo="); pw.println(pkg.toAppInfoWithoutState());
+                pw.print("      applicationInfo=");
+                pw.println(AndroidPackageUtils.generateAppInfoWithoutState(pkg));
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index fb68b23..a3134a0 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -187,6 +187,17 @@
                     .addAction(MediaStore.ACTION_PICK_IMAGES)
                     .addCategory(Intent.CATEGORY_DEFAULT)
                     .build();
+    /** Pick images can be forwarded to parent user. */
+    private static final DefaultCrossProfileIntentFilter ACTION_PICK_IMAGES_WITH_DATA_TYPES =
+            new DefaultCrossProfileIntentFilter.Builder(
+                    DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
+                    /* flags= */ 0,
+                    /* letsPersonalDataIntoProfile= */ true)
+                    .addAction(MediaStore.ACTION_PICK_IMAGES)
+                    .addCategory(Intent.CATEGORY_DEFAULT)
+                    .addDataType("image/*")
+                    .addDataType("video/*")
+                    .build();
 
     /** Open document intent can be forwarded to parent user. */
     private static final DefaultCrossProfileIntentFilter OPEN_DOCUMENT =
@@ -225,7 +236,7 @@
     private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH =
             new DefaultCrossProfileIntentFilter.Builder(
                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
-                    /* flags= */0,
+                    /* flags= */ ONLY_IF_NO_MATCH_FOUND,
                     /* letsPersonalDataIntoProfile= */ false)
                     .addAction(ACTION_RECOGNIZE_SPEECH)
                     .addCategory(Intent.CATEGORY_DEFAULT)
@@ -300,6 +311,7 @@
                 ACTION_PICK_RAW,
                 ACTION_PICK_DATA,
                 ACTION_PICK_IMAGES,
+                ACTION_PICK_IMAGES_WITH_DATA_TYPES,
                 OPEN_DOCUMENT,
                 GET_CONTENT,
                 USB_DEVICE_ATTACHED,
diff --git a/services/core/java/com/android/server/pm/HandlerParams.java b/services/core/java/com/android/server/pm/HandlerParams.java
index b8c2eb8..ab24ee5 100644
--- a/services/core/java/com/android/server/pm/HandlerParams.java
+++ b/services/core/java/com/android/server/pm/HandlerParams.java
@@ -16,20 +16,35 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+
+import android.annotation.NonNull;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
+import android.util.Pair;
 import android.util.Slog;
 
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.TAG;
 
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
 abstract class HandlerParams {
     /** User handle for the user requesting the information or installation. */
     private final UserHandle mUser;
     String mTraceMethod;
     int mTraceCookie;
+    @NonNull
+    final PackageManagerService mPm;
 
-    HandlerParams(UserHandle user) {
+    // TODO(b/198166813): remove PMS dependency
+    HandlerParams(UserHandle user, PackageManagerService pm) {
         mUser = user;
+        mPm = pm;
     }
 
     UserHandle getUser() {
@@ -54,4 +69,135 @@
 
     abstract void handleStartCopy();
     abstract void handleReturnCode();
+
+    Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
+            long requiredInstalledVersionCode, int installFlags) {
+        if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+            return verifyReplacingVersionCodeForApex(
+                    pkgLite, requiredInstalledVersionCode, installFlags);
+        }
+
+        String packageName = pkgLite.packageName;
+        synchronized (mPm.mLock) {
+            // Package which currently owns the data that the new package will own if installed.
+            // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
+            // will be null whereas dataOwnerPkg will contain information about the package
+            // which was uninstalled while keeping its data.
+            AndroidPackage dataOwnerPkg = mPm.mPackages.get(packageName);
+            if (dataOwnerPkg  == null) {
+                PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+                if (ps != null) {
+                    dataOwnerPkg = ps.pkg;
+                }
+            }
+
+            if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
+                if (dataOwnerPkg == null) {
+                    String errorMsg = "Required installed version code was "
+                            + requiredInstalledVersionCode
+                            + " but package is not installed";
+                    Slog.w(TAG, errorMsg);
+                    return Pair.create(
+                            PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
+                }
+
+                if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
+                    String errorMsg = "Required installed version code was "
+                            + requiredInstalledVersionCode
+                            + " but actual installed version is "
+                            + dataOwnerPkg.getLongVersionCode();
+                    Slog.w(TAG, errorMsg);
+                    return Pair.create(
+                            PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
+                }
+            }
+
+            if (dataOwnerPkg != null) {
+                if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
+                        dataOwnerPkg.isDebuggable())) {
+                    try {
+                        checkDowngrade(dataOwnerPkg, pkgLite);
+                    } catch (PackageManagerException e) {
+                        String errorMsg = "Downgrade detected: " + e.getMessage();
+                        Slog.w(TAG, errorMsg);
+                        return Pair.create(
+                                PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
+                    }
+                }
+            }
+        }
+        return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
+    }
+
+    private Pair<Integer, String> verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
+            long requiredInstalledVersionCode, int installFlags) {
+        String packageName = pkgLite.packageName;
+
+        final PackageInfo activePackage = mPm.mApexManager.getPackageInfo(packageName,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
+        if (activePackage == null) {
+            String errorMsg = "Attempting to install new APEX package " + packageName;
+            Slog.w(TAG, errorMsg);
+            return Pair.create(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, errorMsg);
+        }
+
+        final long activeVersion = activePackage.getLongVersionCode();
+        if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
+                && activeVersion != requiredInstalledVersionCode) {
+            String errorMsg = "Installed version of APEX package " + packageName
+                    + " does not match required. Active version: " + activeVersion
+                    + " required: " + requiredInstalledVersionCode;
+            Slog.w(TAG, errorMsg);
+            return Pair.create(PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
+        }
+
+        final boolean isAppDebuggable = (activePackage.applicationInfo.flags
+                & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+        final long newVersionCode = pkgLite.getLongVersionCode();
+        if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
+                && newVersionCode < activeVersion) {
+            String errorMsg = "Downgrade of APEX package " + packageName
+                    + " is not allowed. Active version: " + activeVersion
+                    + " attempted: " + newVersionCode;
+            Slog.w(TAG, errorMsg);
+            return Pair.create(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
+        }
+
+        return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
+    }
+
+    /**
+     * Check and throw if the given before/after packages would be considered a
+     * downgrade.
+     */
+    private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
+            throws PackageManagerException {
+        if (after.getLongVersionCode() < before.getLongVersionCode()) {
+            throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+                    "Update version code " + after.versionCode + " is older than current "
+                            + 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());
+            }
+
+            if (!ArrayUtils.isEmpty(after.splitNames)) {
+                for (int i = 0; i < after.splitNames.length; i++) {
+                    final String splitName = after.splitNames[i];
+                    final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
+                    if (j != -1) {
+                        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]);
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
new file mode 100644
index 0000000..fd00106
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -0,0 +1,1327 @@
+/*
+ * 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.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
+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.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
+import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
+import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
+import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
+import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
+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.decompressFile;
+import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
+import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningDetails;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.system.ErrnoException;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.F2fsUtils;
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.security.VerityUtils;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.EventLogTags;
+import com.android.server.pm.parsing.PackageCacher;
+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.PermissionManagerServiceInternal;
+import com.android.server.utils.WatchedArrayMap;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.DigestException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Part of PackageManagerService that handles init and system packages. This class still needs
+ * further cleanup and eventually all the installation/scanning related logic will go to another
+ * class.
+ */
+public class InitAndSystemPackageHelper {
+    final PackageManagerService mPm;
+
+    // TODO(b/198166813): remove PMS dependency
+    public InitAndSystemPackageHelper(PackageManagerService pm) {
+        mPm = pm;
+    }
+
+    /**
+     * First part of init dir scanning
+     */
+    // TODO(b/197876467): consolidate this with cleanupSystemPackagesAndInstallStubs
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    public void scanSystemDirs(List<ScanPartition>  dirsToScanAsSystem,
+            boolean isUpgrade, PackageParser2 packageParser,
+            ExecutorService executorService, AndroidPackage platformPackage,
+            boolean isPreNMR1Upgrade, int systemParseFlags, int systemScanFlags) {
+        File frameworkDir = new File(Environment.getRootDirectory(), "framework");
+
+        // Collect vendor/product/system_ext overlay packages. (Do this before scanning
+        // any apps.)
+        // For security and version matching reason, only consider overlay packages if they
+        // reside in the right directory.
+        for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
+            final ScanPartition partition = dirsToScanAsSystem.get(i);
+            if (partition.getOverlayFolder() == null) {
+                continue;
+            }
+            scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
+                    systemScanFlags | partition.scanFlag, 0,
+                    packageParser, executorService, platformPackage, isUpgrade,
+                    isPreNMR1Upgrade);
+        }
+
+        scanDirTracedLI(frameworkDir, systemParseFlags,
+                systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+                packageParser, executorService, platformPackage, isUpgrade, isPreNMR1Upgrade);
+        if (!mPm.mPackages.containsKey("android")) {
+            throw new IllegalStateException(
+                    "Failed to load frameworks package; check log for warnings");
+        }
+
+        for (int i = 0, size = dirsToScanAsSystem.size(); i < size; i++) {
+            final ScanPartition partition = dirsToScanAsSystem.get(i);
+            if (partition.getPrivAppFolder() != null) {
+                scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
+                        systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+                        packageParser, executorService, platformPackage, isUpgrade,
+                        isPreNMR1Upgrade);
+            }
+            scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
+                    systemScanFlags | partition.scanFlag, 0,
+                    packageParser, executorService, platformPackage, isUpgrade,
+                    isPreNMR1Upgrade);
+        }
+    }
+
+    /**
+     * Second part of init dir scanning
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    public void cleanupSystemPackagesAndInstallStubs(List<ScanPartition> dirsToScanAsSystem,
+            boolean isUpgrade, PackageParser2 packageParser,
+            ExecutorService executorService, boolean onlyCore,
+            WatchedArrayMap<String, PackageSetting> packageSettings,
+            long startTime, File appInstallDir, AndroidPackage platformPackage,
+            boolean isPreNMR1Upgrade, int scanFlags, int systemParseFlags, int systemScanFlags,
+            int[] userIds) {
+        // Prune any system packages that no longer exist.
+        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
+        // Stub packages must either be replaced with full versions in the /data
+        // partition or be disabled.
+        final List<String> stubSystemApps = new ArrayList<>();
+
+        if (!onlyCore) {
+            // do this first before mucking with mPackages for the "expecting better" case
+            final int numPackages = mPm.mPackages.size();
+            for (int index = 0; index < numPackages; index++) {
+                final AndroidPackage pkg = mPm.mPackages.valueAt(index);
+                if (pkg.isStub()) {
+                    stubSystemApps.add(pkg.getPackageName());
+                }
+            }
+
+            // Iterates PackageSettings in reversed order because the item could be removed
+            // during the iteration.
+            for (int index = packageSettings.size() - 1; index >= 0; index--) {
+                final PackageSetting ps = packageSettings.valueAt(index);
+
+                /*
+                 * If this is not a system app, it can't be a
+                 * disable system app.
+                 */
+                if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    continue;
+                }
+
+                /*
+                 * If the package is scanned, it's not erased.
+                 */
+                final AndroidPackage scannedPkg = mPm.mPackages.get(ps.name);
+                if (scannedPkg != null) {
+                    /*
+                     * If the system app is both scanned and in the
+                     * disabled packages list, then it must have been
+                     * added via OTA. Remove it from the currently
+                     * scanned package so the previously user-installed
+                     * application can be scanned.
+                     */
+                    if (mPm.mSettings.isDisabledSystemPackageLPr(ps.name)) {
+                        logCriticalInfo(Log.WARN,
+                                "Expecting better updated system app for " + ps.name
+                                        + "; removing system app.  Last known"
+                                        + " codePath=" + ps.getPathString()
+                                        + ", versionCode=" + ps.versionCode
+                                        + "; scanned versionCode="
+                                        + scannedPkg.getLongVersionCode());
+                        mPm.removePackageLI(scannedPkg, true);
+                        mPm.mExpectingBetter.put(ps.name, ps.getPath());
+                    }
+
+                    continue;
+                }
+
+                if (!mPm.mSettings.isDisabledSystemPackageLPr(ps.name)) {
+                    logCriticalInfo(Log.WARN, "System package " + ps.name
+                            + " no longer exists; its data will be wiped");
+                    mPm.removePackageDataLIF(ps, userIds, null, 0, false);
+                } else {
+                    // we still have a disabled system package, but, it still might have
+                    // been removed. check the code path still exists and check there's
+                    // still a package. the latter can happen if an OTA keeps the same
+                    // code path, but, changes the package name.
+                    final PackageSetting disabledPs =
+                            mPm.mSettings.getDisabledSystemPkgLPr(ps.name);
+                    if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
+                            || disabledPs.pkg == null) {
+                        possiblyDeletedUpdatedSystemApps.add(ps.name);
+                    } else {
+                        // We're expecting that the system app should remain disabled, but add
+                        // it to expecting better to recover in case the data version cannot
+                        // be scanned.
+                        // TODO(b/197869066): mExpectingBetter should be able to pulled out into
+                        // this class and used only by the PMS initialization
+                        mPm.mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
+                    }
+                }
+            }
+        }
+
+        final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+
+        // Remove any shared userIDs that have no associated packages
+        mPm.mSettings.pruneSharedUsersLPw();
+        final long systemScanTime = SystemClock.uptimeMillis() - startTime;
+        final int systemPackagesCount = mPm.mPackages.size();
+        Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+                + " ms, packageCount: " + systemPackagesCount
+                + " , timePerPackage: "
+                + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+                + " , cached: " + cachedSystemApps);
+        if (isUpgrade && systemPackagesCount > 0) {
+            //CHECKSTYLE:OFF IndentationCheck
+            FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
+                    systemScanTime / systemPackagesCount);
+            //CHECKSTYLE:ON IndentationCheck
+        }
+        if (!onlyCore) {
+            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
+                    SystemClock.uptimeMillis());
+            scanDirTracedLI(appInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
+                    packageParser, executorService, platformPackage, isUpgrade,
+                    isPreNMR1Upgrade);
+
+        }
+
+        List<Runnable> unfinishedTasks = executorService.shutdownNow();
+        if (!unfinishedTasks.isEmpty()) {
+            throw new IllegalStateException("Not all tasks finished before calling close: "
+                    + unfinishedTasks);
+        }
+
+        if (!onlyCore) {
+            // Remove disable package settings for updated system apps that were
+            // removed via an OTA. If the update is no longer present, remove the
+            // app completely. Otherwise, revoke their system privileges.
+            for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
+                final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
+                final AndroidPackage pkg = mPm.mPackages.get(packageName);
+                final String msg;
+
+                // remove from the disabled system list; do this first so any future
+                // scans of this package are performed without this state
+                mPm.mSettings.removeDisabledSystemPackageLPw(packageName);
+
+                if (pkg == null) {
+                    // should have found an update, but, we didn't; remove everything
+                    msg = "Updated system package " + packageName
+                            + " no longer exists; removing its data";
+                    // Actual deletion of code and data will be handled by later
+                    // reconciliation step
+                } else {
+                    // found an update; revoke system privileges
+                    msg = "Updated system package " + packageName
+                            + " no longer exists; rescanning package on data";
+
+                    // NOTE: We don't do anything special if a stub is removed from the
+                    // system image. But, if we were [like removing the uncompressed
+                    // version from the /data partition], this is where it'd be done.
+
+                    // remove the package from the system and re-scan it without any
+                    // special privileges
+                    mPm.removePackageLI(pkg, true);
+                    try {
+                        final File codePath = new File(pkg.getPath());
+                        mPm.scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
+                    } catch (PackageManagerException e) {
+                        Slog.e(TAG, "Failed to parse updated, ex-system package: "
+                                + e.getMessage());
+                    }
+                }
+
+                // one final check. if we still have a package setting [ie. it was
+                // previously scanned and known to the system], but, we don't have
+                // a package [ie. there was an error scanning it from the /data
+                // partition], completely remove the package data.
+                final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+                if (ps != null && mPm.mPackages.get(packageName) == null) {
+                    mPm.removePackageDataLIF(ps, userIds, null, 0, false);
+
+                }
+                logCriticalInfo(Log.WARN, msg);
+            }
+
+            /*
+             * Make sure all system apps that we expected to appear on
+             * the userdata partition actually showed up. If they never
+             * appeared, crawl back and revive the system version.
+             */
+            for (int i = 0; i < mPm.mExpectingBetter.size(); i++) {
+                final String packageName = mPm.mExpectingBetter.keyAt(i);
+                if (!mPm.mPackages.containsKey(packageName)) {
+                    final File scanFile = mPm.mExpectingBetter.valueAt(i);
+
+                    logCriticalInfo(Log.WARN, "Expected better " + packageName
+                            + " but never showed up; reverting to system");
+
+                    @ParsingPackageUtils.ParseFlags int reparseFlags = 0;
+                    @PackageManagerService.ScanFlags int rescanFlags = 0;
+                    for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
+                        final ScanPartition partition = dirsToScanAsSystem.get(i1);
+                        if (partition.containsPrivApp(scanFile)) {
+                            reparseFlags = systemParseFlags;
+                            rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
+                                    | partition.scanFlag;
+                            break;
+                        }
+                        if (partition.containsApp(scanFile)) {
+                            reparseFlags = systemParseFlags;
+                            rescanFlags = systemScanFlags | partition.scanFlag;
+                            break;
+                        }
+                    }
+                    if (rescanFlags == 0) {
+                        Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
+                        continue;
+                    }
+                    mPm.mSettings.enableSystemPackageLPw(packageName);
+
+                    try {
+                        final AndroidPackage newPkg = mPm.scanPackageTracedLI(
+                                scanFile, reparseFlags, rescanFlags, 0, null);
+                        // We rescanned a stub, add it to the list of stubbed system packages
+                        if (newPkg.isStub()) {
+                            stubSystemApps.add(packageName);
+                        }
+                    } catch (PackageManagerException e) {
+                        Slog.e(TAG, "Failed to parse original system package: "
+                                + e.getMessage());
+                    }
+                }
+            }
+
+            // Uncompress and install any stubbed system applications.
+            // This must be done last to ensure all stubs are replaced or disabled.
+            installSystemStubPackages(stubSystemApps, scanFlags);
+
+            final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+                    - cachedSystemApps;
+
+            final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
+            final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
+            Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+                    + " ms, packageCount: " + dataPackagesCount
+                    + " , timePerPackage: "
+                    + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+                    + " , cached: " + cachedNonSystemApps);
+            if (isUpgrade && dataPackagesCount > 0) {
+                //CHECKSTYLE:OFF IndentationCheck
+                FrameworkStatsLog.write(
+                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+                        dataScanTime / dataPackagesCount);
+                //CHECKSTYLE:OFF IndentationCheck
+            }
+        }
+        mPm.mExpectingBetter.clear();
+
+        mPm.mSettings.pruneRenamedPackagesLPw();
+    }
+
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
+            long currentTime, PackageParser2 packageParser, ExecutorService executorService,
+            AndroidPackage platformPackage, boolean isUpgrade, boolean isPreNMR1Upgrade) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
+        try {
+            scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService,
+                    platformPackage, isUpgrade, isPreNMR1Upgrade);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
+            PackageParser2 packageParser, ExecutorService executorService,
+            AndroidPackage platformPackage, boolean isUpgrade, boolean isPreNMR1Upgrade) {
+        final File[] files = scanDir.listFiles();
+        if (ArrayUtils.isEmpty(files)) {
+            Log.d(TAG, "No files in app dir " + scanDir);
+            return;
+        }
+
+        if (DEBUG_PACKAGE_SCANNING) {
+            Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
+                    + " flags=0x" + Integer.toHexString(parseFlags));
+        }
+
+        ParallelPackageParser parallelPackageParser =
+                new ParallelPackageParser(packageParser, executorService);
+
+        // Submit files for parsing in parallel
+        int fileCount = 0;
+        for (File file : files) {
+            final boolean isPackage = (isApkFile(file) || file.isDirectory())
+                    && !PackageInstallerService.isStageName(file.getName());
+            if (!isPackage) {
+                // Ignore entries which are not packages
+                continue;
+            }
+            parallelPackageParser.submit(file, parseFlags);
+            fileCount++;
+        }
+
+        // Process results one by one
+        for (; fileCount > 0; fileCount--) {
+            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+            Throwable throwable = parseResult.throwable;
+            int errorCode = PackageManager.INSTALL_SUCCEEDED;
+            String errorMsg = null;
+
+            if (throwable == null) {
+                // TODO(b/194319951): move lower in the scan chain
+                // Static shared libraries have synthetic package names
+                if (parseResult.parsedPackage.isStaticSharedLibrary()) {
+                    PackageManagerService.renameStaticSharedLibraryPackage(
+                            parseResult.parsedPackage);
+                }
+                try {
+                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
+                            currentTime, null, platformPackage, isUpgrade,
+                            isPreNMR1Upgrade);
+                } catch (PackageManagerException e) {
+                    errorCode = e.error;
+                    errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
+                    Slog.w(TAG, errorMsg);
+                }
+            } else if (throwable instanceof PackageManagerException) {
+                PackageManagerException e = (PackageManagerException) throwable;
+                errorCode = e.error;
+                errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
+                Slog.w(TAG, errorMsg);
+            } else {
+                throw new IllegalStateException("Unexpected exception occurred while parsing "
+                        + parseResult.scanFile, throwable);
+            }
+
+            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
+                mPm.mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
+            }
+
+            // Delete invalid userdata apps
+            if ((scanFlags & SCAN_AS_SYSTEM) == 0
+                    && errorCode != PackageManager.INSTALL_SUCCEEDED) {
+                logCriticalInfo(Log.WARN,
+                        "Deleting invalid package at " + parseResult.scanFile);
+                mPm.removeCodePathLI(parseResult.scanFile);
+            }
+        }
+    }
+
+    /**
+     * Uncompress and install stub applications.
+     * <p>In order to save space on the system partition, some applications are shipped in a
+     * compressed form. In addition the compressed bits for the full application, the
+     * system image contains a tiny stub comprised of only the Android manifest.
+     * <p>During the first boot, attempt to uncompress and install the full application. If
+     * the application can't be installed for any reason, disable the stub and prevent
+     * uncompressing the full application during future boots.
+     * <p>In order to forcefully attempt an installation of a full application, go to app
+     * settings and enable the application.
+     */
+    @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+    private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
+            @PackageManagerService.ScanFlags int scanFlags) {
+        for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+            final String packageName = systemStubPackageNames.get(i);
+            // skip if the system package is already disabled
+            if (mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
+                systemStubPackageNames.remove(i);
+                continue;
+            }
+            // skip if the package isn't installed (?!); this should never happen
+            final AndroidPackage pkg = mPm.mPackages.get(packageName);
+            if (pkg == null) {
+                systemStubPackageNames.remove(i);
+                continue;
+            }
+            // skip if the package has been disabled by the user
+            final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+            if (ps != null) {
+                final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
+                if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+                    systemStubPackageNames.remove(i);
+                    continue;
+                }
+            }
+
+            // install the package to replace the stub on /system
+            try {
+                installStubPackageLI(pkg, 0, scanFlags);
+                ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+                        UserHandle.USER_SYSTEM, "android");
+                systemStubPackageNames.remove(i);
+            } catch (PackageManagerException e) {
+                Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
+            }
+
+            // any failed attempt to install the package will be cleaned up later
+        }
+
+        // disable any stub still left; these failed to install the full application
+        for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+            final String pkgName = systemStubPackageNames.get(i);
+            final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+            ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                    UserHandle.USER_SYSTEM, "android");
+            logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
+        }
+    }
+
+    /**
+     * Extract, install and enable a stub package.
+     * <p>If the compressed file can not be extracted / installed for any reason, the stub
+     * APK will be installed and the package will be disabled. To recover from this situation,
+     * the user will need to go into system settings and re-enable the package.
+     */
+    @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+    public boolean enableCompressedPackage(AndroidPackage stubPkg,
+            @NonNull PackageSetting stubPkgSetting, int defParseFlags,
+            List<ScanPartition> dirsToScanAsSystem) {
+        final int parseFlags = defParseFlags | ParsingPackageUtils.PARSE_CHATTY
+                | ParsingPackageUtils.PARSE_ENFORCE_CODE;
+        synchronized (mPm.mInstallLock) {
+            final AndroidPackage pkg;
+            try (PackageFreezer freezer =
+                         mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
+                pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
+                synchronized (mPm.mLock) {
+                    mPm.prepareAppDataAfterInstallLIF(pkg);
+                    try {
+                        mPm.updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
+                                Collections.unmodifiableMap(mPm.mPackages));
+                    } catch (PackageManagerException e) {
+                        Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
+                    }
+                    mPm.mPermissionManager.onPackageInstalled(pkg,
+                            PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+                            UserHandle.USER_ALL);
+                    mPm.writeSettingsLPrTEMP();
+                }
+            } catch (PackageManagerException e) {
+                // Whoops! Something went very wrong; roll back to the stub and disable the package
+                try (PackageFreezer freezer =
+                             mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
+                    synchronized (mPm.mLock) {
+                        // NOTE: Ensure the system package is enabled; even for a compressed stub.
+                        // If we don't, installing the system package fails during scan
+                        enableSystemPackageLPw(stubPkg);
+                    }
+                    installPackageFromSystemLIF(stubPkg.getPath(),
+                            mPm.mUserManager.getUserIds() /*allUserHandles*/,
+                            null /*origUserHandles*/,
+                            true /*writeSettings*/, defParseFlags, dirsToScanAsSystem);
+                } catch (PackageManagerException pme) {
+                    // Serious WTF; we have to be able to install the stub
+                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
+                            pme);
+                } finally {
+                    // Disable the package; the stub by itself is not runnable
+                    synchronized (mPm.mLock) {
+                        final PackageSetting stubPs = mPm.mSettings.getPackageLPr(
+                                stubPkg.getPackageName());
+                        if (stubPs != null) {
+                            stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
+                                    UserHandle.USER_SYSTEM, "android");
+                        }
+                        mPm.writeSettingsLPrTEMP();
+                    }
+                }
+                return false;
+            }
+            mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+                    | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
+                    pkg.getBaseApkPath(), pkg.getSplitCodePaths());
+        }
+        return true;
+    }
+
+    @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+    private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
+            @ParsingPackageUtils.ParseFlags int parseFlags,
+            @PackageManagerService.ScanFlags int scanFlags)
+            throws PackageManagerException {
+        if (DEBUG_COMPRESSION) {
+            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
+        }
+        // uncompress the binary to its eventual destination on /data
+        final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
+        if (scanFile == null) {
+            throw new PackageManagerException(
+                    "Unable to decompress stub at " + stubPkg.getPath());
+        }
+        synchronized (mPm.mLock) {
+            mPm.mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
+        }
+        mPm.removePackageLI(stubPkg, true /*chatty*/);
+        try {
+            return mPm.scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+        } catch (PackageManagerException e) {
+            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
+                    e);
+            // Remove the failed install
+            mPm.removeCodePathLI(scanFile);
+            throw e;
+        }
+    }
+
+    /**
+     * Decompresses the given package on the system image onto
+     * the /data partition.
+     * @return The directory the package was decompressed into. Otherwise, {@code null}.
+     */
+    @GuardedBy("mPm.mInstallLock")
+    private File decompressPackage(String packageName, String codePath) {
+        final File[] compressedFiles = getCompressedFiles(codePath);
+        if (compressedFiles == null || compressedFiles.length == 0) {
+            if (DEBUG_COMPRESSION) {
+                Slog.i(TAG, "No files to decompress: " + codePath);
+            }
+            return null;
+        }
+        final File dstCodePath =
+                PackageManagerService.getNextCodePath(Environment.getDataAppDirectory(null),
+                        packageName);
+        int ret = PackageManager.INSTALL_SUCCEEDED;
+        try {
+            makeDirRecursive(dstCodePath, 0755);
+            for (File srcFile : compressedFiles) {
+                final String srcFileName = srcFile.getName();
+                final String dstFileName = srcFileName.substring(
+                        0, srcFileName.length() - COMPRESSED_EXTENSION.length());
+                final File dstFile = new File(dstCodePath, dstFileName);
+                ret = decompressFile(srcFile, dstFile);
+                if (ret != PackageManager.INSTALL_SUCCEEDED) {
+                    logCriticalInfo(Log.ERROR, "Failed to decompress"
+                            + "; pkg: " + packageName
+                            + ", file: " + dstFileName);
+                    break;
+                }
+            }
+        } catch (ErrnoException e) {
+            logCriticalInfo(Log.ERROR, "Failed to decompress"
+                    + "; pkg: " + packageName
+                    + ", err: " + e.errno);
+        }
+        if (ret == PackageManager.INSTALL_SUCCEEDED) {
+            final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
+            NativeLibraryHelper.Handle handle = null;
+            try {
+                handle = NativeLibraryHelper.Handle.create(dstCodePath);
+                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
+                        null /*abiOverride*/, false /*isIncremental*/);
+            } catch (IOException e) {
+                logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
+                        + "; pkg: " + packageName);
+                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            } finally {
+                IoUtils.closeQuietly(handle);
+            }
+        }
+        if (ret == PackageManager.INSTALL_SUCCEEDED) {
+            // NOTE: During boot, we have to delay releasing cblocks for no other reason than
+            // we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}.
+            // When we no longer need to read that setting, cblock release can occur always
+            // occur here directly
+            if (!mPm.mSystemReady) {
+                if (mPm.mReleaseOnSystemReady == null) {
+                    mPm.mReleaseOnSystemReady = new ArrayList<>();
+                }
+                mPm.mReleaseOnSystemReady.add(dstCodePath);
+            } else {
+                final ContentResolver resolver = mPm.mContext.getContentResolver();
+                F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
+            }
+        }
+        if (ret != PackageManager.INSTALL_SUCCEEDED) {
+            if (!dstCodePath.exists()) {
+                return null;
+            }
+            mPm.removeCodePathLI(dstCodePath);
+            return null;
+        }
+
+        return dstCodePath;
+    }
+
+
+    @GuardedBy("mPm.mLock")
+    private void enableSystemPackageLPw(AndroidPackage pkg) {
+        mPm.mSettings.enableSystemPackageLPw(pkg.getPackageName());
+    }
+
+    /**
+     * Tries to delete system package.
+     */
+    @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+    public void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs,
+            @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
+            boolean writeSettings, int defParseFlags, List<ScanPartition> dirsToScanAsSystem)
+            throws SystemDeleteException {
+        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.mDisabledPs;
+        if (DEBUG_REMOVE) {
+            Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
+                    + " disabledPs=" + disabledPs);
+        }
+        Slog.d(TAG, "Deleting system pkg from data partition");
+
+        if (DEBUG_REMOVE) {
+            if (applyUserRestrictions) {
+                Slog.d(TAG, "Remembering install states:");
+                for (int userId : allUserHandles) {
+                    final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId);
+                    Slog.d(TAG, "   u=" + userId + " inst=" + finstalled);
+                }
+            }
+        }
+
+        if (outInfo != null) {
+            // Delete the updated package
+            outInfo.mIsRemovedPackageSystemUpdate = true;
+        }
+
+        if (disabledPs.versionCode < deletedPs.versionCode) {
+            // Delete data for downgrades
+            flags &= ~PackageManager.DELETE_KEEP_DATA;
+        } else {
+            // Preserve data by setting flag
+            flags |= PackageManager.DELETE_KEEP_DATA;
+        }
+
+        mPm.deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
+                outInfo, writeSettings);
+
+        // writer
+        synchronized (mPm.mLock) {
+            // NOTE: The system package always needs to be enabled; even if it's for
+            // a compressed stub. If we don't, installing the system package fails
+            // during scan [scanning checks the disabled packages]. We will reverse
+            // this later, after we've "installed" the stub.
+            // Reinstate the old system package
+            enableSystemPackageLPw(disabledPs.pkg);
+            // Remove any native libraries from the upgraded package.
+            removeNativeBinariesLI(deletedPs);
+        }
+
+        // Install the system package
+        if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
+        try {
+            installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
+                    outInfo == null ? null : outInfo.mOrigUsers, writeSettings, defParseFlags,
+                    dirsToScanAsSystem);
+        } catch (PackageManagerException e) {
+            Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+                    + e.getMessage());
+            // TODO(b/194319951): can we avoid this; throw would come from scan...
+            throw new SystemDeleteException(e);
+        } finally {
+            if (disabledPs.pkg.isStub()) {
+                // We've re-installed the stub; make sure it's disabled here. If package was
+                // originally enabled, we'll install the compressed version of the application
+                // and re-enable it afterward.
+                final PackageSetting stubPs = mPm.mSettings.getPackageLPr(
+                        deletedPkg.getPackageName());
+                if (stubPs != null) {
+                    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");
+                        }
+                    } else if (userId >= UserHandle.USER_SYSTEM) {
+                        stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
+                    }
+                }
+            }
+        }
+    }
+
+    private void removeNativeBinariesLI(PackageSetting ps) {
+        if (ps != null) {
+            NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
+        }
+    }
+
+    /**
+     * Installs a package that's already on the system partition.
+     */
+    @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+    private void installPackageFromSystemLIF(@NonNull String codePathString,
+            @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings,
+            int defParseFlags, List<ScanPartition> dirsToScanAsSystem)
+            throws PackageManagerException {
+        final File codePath = new File(codePathString);
+        @ParsingPackageUtils.ParseFlags int parseFlags =
+                defParseFlags
+                        | ParsingPackageUtils.PARSE_MUST_BE_APK
+                        | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
+        @PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
+        for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
+            ScanPartition partition = dirsToScanAsSystem.get(i);
+            if (partition.containsFile(codePath)) {
+                scanFlags |= partition.scanFlag;
+                if (partition.containsPrivApp(codePath)) {
+                    scanFlags |= SCAN_AS_PRIVILEGED;
+                }
+                break;
+            }
+        }
+
+        final AndroidPackage pkg =
+                mPm.scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+
+        PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+
+        try {
+            // update shared libraries for the newly re-installed system package
+            mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+                    Collections.unmodifiableMap(mPm.mPackages));
+        } catch (PackageManagerException e) {
+            Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+        }
+
+        mPm.prepareAppDataAfterInstallLIF(pkg);
+
+        // writer
+        synchronized (mPm.mLock) {
+            PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+
+            final boolean applyUserRestrictions = origUserHandles != null;
+            if (applyUserRestrictions) {
+                boolean installedStateChanged = false;
+                if (DEBUG_REMOVE) {
+                    Slog.d(TAG, "Propagating install state across reinstall");
+                }
+                for (int userId : allUserHandles) {
+                    final boolean installed = ArrayUtils.contains(origUserHandles, userId);
+                    if (DEBUG_REMOVE) {
+                        Slog.d(TAG, "    user " + userId + " => " + installed);
+                    }
+                    if (installed != ps.getInstalled(userId)) {
+                        installedStateChanged = true;
+                    }
+                    ps.setInstalled(installed, userId);
+                    if (installed) {
+                        ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
+                    }
+                }
+                // Regardless of writeSettings we need to ensure that this restriction
+                // state propagation is persisted
+                mPm.mSettings.writeAllUsersPackageRestrictionsLPr();
+                if (installedStateChanged) {
+                    mPm.mSettings.writeKernelMappingLPr(ps);
+                }
+            }
+
+            // The method below will take care of removing obsolete permissions and granting
+            // install permissions.
+            mPm.mPermissionManager.onPackageInstalled(pkg,
+                    PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+                    UserHandle.USER_ALL);
+            for (final int userId : allUserHandles) {
+                if (applyUserRestrictions) {
+                    mPm.mSettings.writePermissionStateForUserLPr(userId, false);
+                }
+            }
+
+            // can downgrade to reader here
+            if (writeSettings) {
+                mPm.writeSettingsLPrTEMP();
+            }
+        }
+    }
+
+    /**
+     * Adds a new package to the internal data structures during platform initialization.
+     * <p>After adding, the package is known to the system and available for querying.
+     * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
+     * etc...], additional checks are performed. Basic verification [such as ensuring
+     * matching signatures, checking version codes, etc...] occurs if the package is
+     * identical to a previously known package. If the package fails a signature check,
+     * the version installed on /data will be removed. If the version of the new package
+     * is less than or equal than the version on /data, it will be ignored.
+     * <p>Regardless of the package location, the results are applied to the internal
+     * structures and the package is made available to the rest of the system.
+     * <p>NOTE: The return value should be removed. It's the passed in package object.
+     */
+    @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+    public AndroidPackage addForInitLI(ParsedPackage parsedPackage,
+            @ParsingPackageUtils.ParseFlags int parseFlags,
+            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+            @Nullable UserHandle user, AndroidPackage platformPackage, boolean isUpgrade,
+            boolean isPreNMR1Upgrade) throws PackageManagerException {
+        final boolean scanSystemPartition =
+                (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
+        final String renamedPkgName;
+        final PackageSetting disabledPkgSetting;
+        final boolean isSystemPkgUpdated;
+        final boolean pkgAlreadyExists;
+        PackageSetting pkgSetting;
+
+        synchronized (mPm.mLock) {
+            renamedPkgName = mPm.mSettings.getRenamedPackageLPr(
+                    AndroidPackageUtils.getRealPackageOrNull(parsedPackage));
+            final String realPkgName = PackageManagerService.getRealPackageName(parsedPackage,
+                    renamedPkgName);
+            if (realPkgName != null) {
+                PackageManagerService.ensurePackageRenamed(parsedPackage, renamedPkgName);
+            }
+            final PackageSetting originalPkgSetting = mPm.getOriginalPackageLocked(parsedPackage,
+                    renamedPkgName);
+            final PackageSetting installedPkgSetting = mPm.mSettings.getPackageLPr(
+                    parsedPackage.getPackageName());
+            pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
+            pkgAlreadyExists = pkgSetting != null;
+            final String disabledPkgName = pkgAlreadyExists
+                    ? pkgSetting.name : parsedPackage.getPackageName();
+            if (scanSystemPartition && !pkgAlreadyExists
+                    && mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
+                // The updated-package data for /system apk remains inconsistently
+                // after the package data for /data apk is lost accidentally.
+                // To recover it, enable /system apk and install it as non-updated system app.
+                Slog.w(TAG, "Inconsistent package setting of updated system app for "
+                        + disabledPkgName + ". To recover it, enable the system app"
+                        + "and install it as non-updated system app.");
+                mPm.mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
+            }
+            disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName);
+            isSystemPkgUpdated = disabledPkgSetting != null;
+
+            if (DEBUG_INSTALL && isSystemPkgUpdated) {
+                Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
+            }
+
+            final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
+                    ? mPm.mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
+                    0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
+                    : null;
+            if (DEBUG_PACKAGE_SCANNING
+                    && (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
+                    && sharedUserSetting != null) {
+                Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
+                        + " (uid=" + sharedUserSetting.userId + "):"
+                        + " packages=" + sharedUserSetting.packages);
+            }
+
+            if (scanSystemPartition) {
+                if (isSystemPkgUpdated) {
+                    // we're updating the disabled package, so, scan it as the package setting
+                    boolean isPlatformPackage = platformPackage != null
+                            && Objects.equals(platformPackage.getPackageName(),
+                            parsedPackage.getPackageName());
+                    final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
+                            null, disabledPkgSetting /* pkgSetting */,
+                            null /* disabledPkgSetting */, null /* originalPkgSetting */,
+                            null, parseFlags, scanFlags, isPlatformPackage, user, null);
+                    PackageManagerService.applyPolicy(parsedPackage, scanFlags,
+                            platformPackage, true);
+                    final ScanResult scanResult =
+                            mPm.scanPackageOnlyLI(request, mPm.mInjector,
+                                    mPm.mFactoryTest, -1L);
+                    if (scanResult.mExistingSettingCopied
+                            && scanResult.mRequest.mPkgSetting != null) {
+                        scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting);
+                    }
+                }
+            }
+        }
+
+        final boolean newPkgChangedPaths = pkgAlreadyExists
+                && !pkgSetting.getPathString().equals(parsedPackage.getPath());
+        final boolean newPkgVersionGreater =
+                pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
+        final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
+                && newPkgChangedPaths && newPkgVersionGreater;
+        if (isSystemPkgBetter) {
+            // The version of the application on /system is greater than the version on
+            // /data. Switch back to the application on /system.
+            // It's safe to assume the application on /system will correctly scan. If not,
+            // there won't be a working copy of the application.
+            synchronized (mPm.mLock) {
+                // just remove the loaded entries from package lists
+                mPm.mPackages.remove(pkgSetting.name);
+            }
+
+            logCriticalInfo(Log.WARN,
+                    "System package updated;"
+                            + " name: " + pkgSetting.name
+                            + "; " + pkgSetting.versionCode + " --> "
+                            + parsedPackage.getLongVersionCode()
+                            + "; " + pkgSetting.getPathString()
+                            + " --> " + parsedPackage.getPath());
+
+            final InstallArgs args = mPm.createInstallArgsForExisting(
+                    pkgSetting.getPathString(), getAppDexInstructionSets(
+                            pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
+            args.cleanUpResourcesLI();
+            synchronized (mPm.mLock) {
+                mPm.mSettings.enableSystemPackageLPw(pkgSetting.name);
+            }
+        }
+
+        // The version of the application on the /system partition is less than or
+        // equal to the version on the /data partition. Throw an exception and use
+        // the application already installed on the /data partition.
+        if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
+            // In the case of a skipped package, commitReconciledScanResultLocked is not called to
+            // add the object to the "live" data structures, so this is the final mutation step
+            // 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.hideAsFinal();
+            throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+                    + " at " + parsedPackage.getPath() + " ignored: updated version "
+                    + (pkgAlreadyExists ? String.valueOf(pkgSetting.versionCode) : "unknown")
+                    + " better than this " + parsedPackage.getLongVersionCode());
+        }
+
+        // Verify certificates against what was last scanned. Force re-collecting certificate in two
+        // special cases:
+        // 1) when scanning system, force re-collect only if system is upgrading.
+        // 2) when scannning /data, force re-collect only if the app is privileged (updated from
+        // preinstall, or treated as privileged, e.g. due to shared user ID).
+        final boolean forceCollect = scanSystemPartition ? isUpgrade
+                : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
+        if (DEBUG_VERIFY && forceCollect) {
+            Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
+        }
+
+        // Full APK verification can be skipped during certificate collection, only if the file is
+        // in verified partition, or can be verified on access (when apk verity is enabled). In both
+        // cases, only data in Signing Block is verified instead of the whole file.
+        // TODO(b/136132412): skip for Incremental installation
+        final boolean skipVerify = scanSystemPartition
+                || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
+        collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify,
+                isPreNMR1Upgrade);
+
+        // Reset profile if the application version is changed
+        maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
+
+        /*
+         * A new system app appeared, but we already had a non-system one of the
+         * same name installed earlier.
+         */
+        boolean shouldHideSystemApp = false;
+        // A new application appeared on /system, but, we already have a copy of
+        // the application installed on /data.
+        if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
+                && !pkgSetting.isSystem()) {
+
+            if (!parsedPackage.getSigningDetails()
+                    .checkCapability(pkgSetting.signatures.mSigningDetails,
+                            SigningDetails.CertCapabilities.INSTALLED_DATA)
+                    && !pkgSetting.signatures.mSigningDetails.checkCapability(
+                    parsedPackage.getSigningDetails(),
+                    SigningDetails.CertCapabilities.ROLLBACK)) {
+                logCriticalInfo(Log.WARN,
+                        "System package signature mismatch;"
+                                + " name: " + pkgSetting.name);
+                try (@SuppressWarnings("unused") PackageFreezer freezer = mPm.freezePackage(
+                        parsedPackage.getPackageName(),
+                        "scanPackageInternalLI")) {
+                    mPm.deletePackageLIF(parsedPackage.getPackageName(), null, true,
+                            mPm.mUserManager.getUserIds(), 0, null, false);
+                }
+                pkgSetting = null;
+            } else if (newPkgVersionGreater) {
+                // The application on /system is newer than the application on /data.
+                // Simply remove the application on /data [keeping application data]
+                // and replace it with the version on /system.
+                logCriticalInfo(Log.WARN,
+                        "System package enabled;"
+                                + " name: " + pkgSetting.name
+                                + "; " + pkgSetting.versionCode + " --> "
+                                + parsedPackage.getLongVersionCode()
+                                + "; " + pkgSetting.getPathString() + " --> "
+                                + parsedPackage.getPath());
+                InstallArgs args = mPm.createInstallArgsForExisting(
+                        pkgSetting.getPathString(), getAppDexInstructionSets(
+                                pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
+                synchronized (mPm.mInstallLock) {
+                    args.cleanUpResourcesLI();
+                }
+            } else {
+                // The application on /system is older than the application on /data. Hide
+                // the application on /system and the version on /data will be scanned later
+                // and re-added like an update.
+                shouldHideSystemApp = true;
+                logCriticalInfo(Log.INFO,
+                        "System package disabled;"
+                                + " name: " + pkgSetting.name
+                                + "; old: " + pkgSetting.getPathString() + " @ "
+                                + pkgSetting.versionCode
+                                + "; new: " + parsedPackage.getPath() + " @ "
+                                + parsedPackage.getPath());
+            }
+        }
+
+        final ScanResult scanResult = mPm.scanPackageNewLI(parsedPackage, parseFlags, scanFlags
+                | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+        if (scanResult.mSuccess) {
+            synchronized (mPm.mLock) {
+                boolean appIdCreated = false;
+                try {
+                    final String pkgName = scanResult.mPkgSetting.name;
+                    final Map<String, ReconciledPackage> reconcileResult =
+                            mPm.reconcilePackagesLocked(
+                            new ReconcileRequest(
+                                    Collections.singletonMap(pkgName, scanResult),
+                                    mPm.mSharedLibraries,
+                                    mPm.mPackages,
+                                    Collections.singletonMap(
+                                            pkgName,
+                                            mPm.getSettingsVersionForPackage(parsedPackage)),
+                                    Collections.singletonMap(pkgName,
+                                            mPm.getSharedLibLatestVersionSetting(scanResult))),
+                                    mPm.mSettings.getKeySetManagerService(), mPm.mInjector);
+                    appIdCreated = mPm.optimisticallyRegisterAppId(scanResult);
+                    mPm.commitReconciledScanResultLocked(
+                            reconcileResult.get(pkgName), mPm.mUserManager.getUserIds());
+                } catch (PackageManagerException e) {
+                    if (appIdCreated) {
+                        mPm.cleanUpAppIdCreation(scanResult);
+                    }
+                    throw e;
+                }
+            }
+        }
+
+        if (shouldHideSystemApp) {
+            synchronized (mPm.mLock) {
+                mPm.mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
+            }
+        }
+        if (mPm.mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) {
+            if (pkgSetting != null && pkgSetting.isPackageLoading()) {
+                // Continue monitoring loading progress of active incremental packages
+                final IncrementalStatesCallback incrementalStatesCallback =
+                        new IncrementalStatesCallback(parsedPackage.getPackageName(), mPm);
+                pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
+                mPm.mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
+                        new IncrementalProgressListener(parsedPackage.getPackageName(), mPm));
+            }
+        }
+        return scanResult.mPkgSetting.pkg;
+    }
+
+    /**
+     * Returns if forced apk verification can be skipped for the whole package, including splits.
+     */
+    private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
+        if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
+            return false;
+        }
+        // TODO: Allow base and splits to be verified individually.
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if (!canSkipForcedApkVerification(splitCodePaths[i])) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
+     * whether the apk contains signed root hash.  Note that the signer's certificate still needs to
+     * match one in a trusted source, and should be done separately.
+     */
+    private boolean canSkipForcedApkVerification(String apkPath) {
+        if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
+            return VerityUtils.hasFsverity(apkPath);
+        }
+
+        try {
+            final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
+            if (rootHashObserved == null) {
+                return false;  // APK does not contain Merkle tree root hash.
+            }
+            synchronized (mPm.mInstallLock) {
+                // Returns whether the observed root hash matches what kernel has.
+                mPm.mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
+                return true;
+            }
+        } catch (Installer.InstallerException | IOException | DigestException
+                | NoSuchAlgorithmException e) {
+            Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
+        }
+        return false;
+    }
+
+    private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
+            boolean forceCollect, boolean skipVerify, boolean mIsPreNMR1Upgrade)
+            throws PackageManagerException {
+        // When upgrading from pre-N MR1, verify the package time stamp using the package
+        // directory and not the APK file.
+        final long lastModifiedTime = mIsPreNMR1Upgrade
+                ? new File(parsedPackage.getPath()).lastModified()
+                : getLastModifiedTime(parsedPackage);
+        final Settings.VersionInfo settingsVersionForPackage =
+                mPm.getSettingsVersionForPackage(parsedPackage);
+        if (ps != null && !forceCollect
+                && ps.getPathString().equals(parsedPackage.getPath())
+                && ps.timeStamp == lastModifiedTime
+                && !PackageManagerService.isCompatSignatureUpdateNeeded(settingsVersionForPackage)
+                && !PackageManagerService.isRecoverSignatureUpdateNeeded(
+                        settingsVersionForPackage)) {
+            if (ps.signatures.mSigningDetails.getSignatures() != null
+                    && ps.signatures.mSigningDetails.getSignatures().length != 0
+                    && ps.signatures.mSigningDetails.getSignatureSchemeVersion()
+                    != SigningDetails.SignatureSchemeVersion.UNKNOWN) {
+                // Optimization: reuse the existing cached signing data
+                // if the package appears to be unchanged.
+                parsedPackage.setSigningDetails(
+                        new SigningDetails(ps.signatures.mSigningDetails));
+                return;
+            }
+
+            Slog.w(TAG, "PackageSetting for " + ps.name
+                    + " is missing signatures.  Collecting certs again to recover them.");
+        } else {
+            Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs"
+                    + (forceCollect ? " (forced)" : ""));
+        }
+
+        try {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
+                    input, parsedPackage, skipVerify);
+            if (result.isError()) {
+                throw new PackageManagerException(
+                        result.getErrorCode(), result.getErrorMessage(), result.getException());
+            }
+            parsedPackage.setSigningDetails(result.getResult());
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    /**
+     * Clear the package profile if this was an upgrade and the package
+     * version was updated.
+     */
+    private void maybeClearProfilesForUpgradesLI(
+            @Nullable PackageSetting originalPkgSetting,
+            @NonNull AndroidPackage pkg) {
+        if (originalPkgSetting == null || !mPm.isDeviceUpgrading()) {
+            return;
+        }
+        if (originalPkgSetting.versionCode == pkg.getLongVersionCode()) {
+            return;
+        }
+
+        mPm.clearAppProfilesLIF(pkg);
+        if (DEBUG_INSTALL) {
+            Slog.d(TAG, originalPkgSetting.name
+                    + " clear profile due to version change "
+                    + originalPkgSetting.versionCode + " != "
+                    + pkg.getLongVersionCode());
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index e87dbed..934775a 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -163,14 +163,12 @@
     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;
+        super(user, pm);
         mOriginInfo = originInfo;
         mMoveInfo = moveInfo;
         mObserver = observer;
@@ -195,8 +193,7 @@
             PackageInstaller.SessionParams sessionParams, InstallSource installSource,
             UserHandle user, SigningDetails signingDetails, int installerUid,
             PackageLite packageLite, PackageManagerService pm) {
-        super(user);
-        mPm = pm;
+        super(user, pm);
         mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
         mMoveInfo = null;
         mInstallReason = fixUpInstallReason(
@@ -373,7 +370,7 @@
         // 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(
+            Pair<Integer, String> ret = verifyReplacingVersionCode(
                     pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
             mRet = ret.first;
             if (mRet != INSTALL_SUCCEEDED) {
@@ -622,7 +619,7 @@
                 Map<String, ReconciledPackage> reconciledPackages;
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
-                    reconciledPackages = PackageManagerService.reconcilePackagesLocked(
+                    reconciledPackages = mPm.reconcilePackagesLocked(
                             reconcileRequest, mPm.mSettings.getKeySetManagerService(),
                             mPm.mInjector);
                 } catch (ReconcileFailure e) {
@@ -1207,7 +1204,10 @@
                     // Check for shared user id changes
                     String invalidPackageName = null;
                     if (!Objects.equals(oldPackage.getSharedUserId(),
-                            parsedPackage.getSharedUserId())) {
+                            parsedPackage.getSharedUserId())
+                            // Don't mark as invalid if the app is trying to
+                            // leave a sharedUserId
+                            && parsedPackage.getSharedUserId() != null) {
                         invalidPackageName = parsedPackage.getPackageName();
                     }
 
@@ -2072,7 +2072,7 @@
             throws PackageManagerException {
         final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
         final MultiPackageInstallParams params =
-                new MultiPackageInstallParams(this, children);
+                new MultiPackageInstallParams(this, children, mPm);
         params.setTraceMethod("installStageMultiPackage")
                 .setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
@@ -2104,9 +2104,10 @@
         private final List<InstallParams> mChildParams;
         private final Map<InstallArgs, Integer> mCurrentState;
 
-        MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
+        MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams,
+                PackageManagerService pm)
                 throws PackageManagerException {
-            super(parent.getUser());
+            super(parent.getUser(), pm);
             if (childParams.size() == 0) {
                 throw new PackageManagerException("No child sessions found!");
             }
@@ -2156,4 +2157,6 @@
                     installRequests);
         }
     }
+
+
 }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index d4ebbe3..4709ba1 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -56,6 +56,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
@@ -618,7 +619,8 @@
         }
 
         // TODO(b/135203078): Remove toAppInfo call? Requires significant additions/changes to PM
-        Drawable icon = pkg.toAppInfoWithoutState().loadIcon(mService.mContext.getPackageManager());
+        Drawable icon = AndroidPackageUtils.generateAppInfoWithoutState(pkg)
+                .loadIcon(mService.mContext.getPackageManager());
 
         final Bitmap bitmap;
         if (icon instanceof BitmapDrawable) {
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 1b919f9..98eef07 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -343,7 +343,7 @@
         return mKeySets.get(id) != null;
     }
 
-    public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) {
+    public boolean shouldCheckUpgradeKeySetLocked(PackageSetting oldPs, int scanFlags) {
         // Can't rotate keys during boot or if sharedUser.
         if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
                 || !oldPs.keySetData.isUsingUpgradeKeySets()) {
@@ -364,7 +364,7 @@
         return true;
     }
 
-    public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, AndroidPackage pkg) {
+    public boolean checkUpgradeKeySetLocked(PackageSetting oldPS, AndroidPackage pkg) {
         // Upgrade keysets are being used.  Determine if new package has a superset of the
         // required keys.
         long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index d851e6c..bf1fe31 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -136,9 +136,9 @@
             boolean isUpdatedSystemApp, File appLib32InstallDir) {
         // Trying to derive the paths, thus need the raw ABI info from the parsed package, and the
         // current state in PackageSetting is irrelevant.
-        return deriveNativeLibraryPaths(new Abis(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()),
-                appLib32InstallDir, pkg.getPath(), pkg.getBaseApkPath(), pkg.isSystem(),
-                isUpdatedSystemApp);
+        return deriveNativeLibraryPaths(new Abis(AndroidPackageUtils.getRawPrimaryCpuAbi(pkg),
+                AndroidPackageUtils.getRawSecondaryCpuAbi(pkg)), appLib32InstallDir, pkg.getPath(),
+                pkg.getBaseApkPath(), pkg.isSystem(), isUpdatedSystemApp);
     }
 
     private static NativeLibraryPaths deriveNativeLibraryPaths(final Abis abis,
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
new file mode 100644
index 0000000..a5a6cae
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -0,0 +1,784 @@
+/*
+ * 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.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
+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_BACKUP;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE;
+import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_INSTALL_OBSERVER;
+import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE;
+import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
+import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_STATUS;
+import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
+import static com.android.server.pm.PackageManagerService.INIT_COPY;
+import static com.android.server.pm.PackageManagerService.INSTANT_APP_RESOLUTION_PHASE_TWO;
+import static com.android.server.pm.PackageManagerService.INTEGRITY_VERIFICATION_COMPLETE;
+import static com.android.server.pm.PackageManagerService.PACKAGE_VERIFIED;
+import static com.android.server.pm.PackageManagerService.POST_INSTALL;
+import static com.android.server.pm.PackageManagerService.SEND_PENDING_BROADCAST;
+import static com.android.server.pm.PackageManagerService.SNAPSHOT_UNCORK;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerService.TRACE_SNAPSHOTS;
+import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_LIST;
+import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_RESTRICTIONS;
+import static com.android.server.pm.PackageManagerService.WRITE_SETTINGS;
+
+import android.content.Intent;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.InstantAppRequest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.stats.storage.StorageEnums;
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.EventLogTags;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import dalvik.system.VMRuntime;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Part of PackageManagerService that handles events.
+ */
+public class PackageHandler extends Handler {
+    final PackageManagerService mPm;
+    PackageHandler(Looper looper, PackageManagerService pm) {
+        super(looper);
+        mPm = pm;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        try {
+            doHandleMessage(msg);
+        } finally {
+            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+        }
+    }
+
+    void doHandleMessage(Message msg) {
+        switch (msg.what) {
+            case INIT_COPY: {
+                HandlerParams params = (HandlerParams) msg.obj;
+                if (params != null) {
+                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
+                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                            System.identityHashCode(params));
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
+                    params.startCopy();
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                break;
+            }
+            case SEND_PENDING_BROADCAST: {
+                String[] packages;
+                ArrayList<String>[] components;
+                int size = 0;
+                int[] uids;
+                Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+                synchronized (mPm.mLock) {
+                    size = mPm.mPendingBroadcasts.size();
+                    if (size <= 0) {
+                        // Nothing to be done. Just return
+                        return;
+                    }
+                    packages = new String[size];
+                    components = new ArrayList[size];
+                    uids = new int[size];
+                    int i = 0;  // filling out the above arrays
+
+                    for (int n = 0; n < mPm.mPendingBroadcasts.userIdCount(); n++) {
+                        final int packageUserId = mPm.mPendingBroadcasts.userIdAt(n);
+                        final ArrayMap<String, ArrayList<String>> componentsToBroadcast =
+                                mPm.mPendingBroadcasts.packagesForUserId(packageUserId);
+                        final int numComponents = componentsToBroadcast.size();
+                        for (int index = 0; i < size && index < numComponents; index++) {
+                            packages[i] = componentsToBroadcast.keyAt(index);
+                            components[i] = componentsToBroadcast.valueAt(index);
+                            final PackageSetting ps = mPm.mSettings.getPackageLPr(packages[i]);
+                            uids[i] = (ps != null)
+                                    ? UserHandle.getUid(packageUserId, ps.appId)
+                                    : -1;
+                            i++;
+                        }
+                    }
+                    size = i;
+                    mPm.mPendingBroadcasts.clear();
+                }
+                // Send broadcasts
+                for (int i = 0; i < size; i++) {
+                    mPm.sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
+                            components[i], uids[i], null /* reason */);
+                }
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                break;
+            }
+            case POST_INSTALL: {
+                if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
+
+                PackageManagerService.PostInstallData data = mPm.mRunningInstalls.get(msg.arg1);
+                final boolean didRestore = (msg.arg2 != 0);
+                mPm.mRunningInstalls.delete(msg.arg1);
+
+                if (data != null && data.res.mFreezer != null) {
+                    data.res.mFreezer.close();
+                }
+
+                if (data != null && data.mPostInstallRunnable != null) {
+                    data.mPostInstallRunnable.run();
+                } else if (data != null && data.args != null) {
+                    InstallArgs args = data.args;
+                    PackageInstalledInfo parentRes = data.res;
+
+                    final boolean killApp = (args.mInstallFlags
+                            & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+                    final boolean virtualPreload = ((args.mInstallFlags
+                            & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
+
+                    handlePackagePostInstall(parentRes, killApp, virtualPreload,
+                            didRestore, args.mInstallSource.installerPackageName,
+                            args.mObserver, args.mDataLoaderType);
+
+                    // Log tracing if needed
+                    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
+                    Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
+                }
+
+                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
+            } break;
+            case DEFERRED_NO_KILL_POST_DELETE: {
+                synchronized (mPm.mInstallLock) {
+                    InstallArgs args = (InstallArgs) msg.obj;
+                    if (args != null) {
+                        args.doPostDeleteLI(true);
+                    }
+                }
+            } break;
+            case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
+                String packageName = (String) msg.obj;
+                if (packageName != null) {
+                    mPm.notifyInstallObserver(packageName);
+                }
+            } break;
+            case WRITE_SETTINGS: {
+                Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+                synchronized (mPm.mLock) {
+                    removeMessages(WRITE_SETTINGS);
+                    removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+                    mPm.writeSettingsLPrTEMP();
+                    mPm.mDirtyUsers.clear();
+                }
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+            } break;
+            case WRITE_PACKAGE_RESTRICTIONS: {
+                Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+                synchronized (mPm.mLock) {
+                    removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+                    for (int userId : mPm.mDirtyUsers) {
+                        mPm.mSettings.writePackageRestrictionsLPr(userId);
+                    }
+                    mPm.mDirtyUsers.clear();
+                }
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+            } break;
+            case WRITE_PACKAGE_LIST: {
+                Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+                synchronized (mPm.mLock) {
+                    removeMessages(WRITE_PACKAGE_LIST);
+                    mPm.mSettings.writePackageListLPr(msg.arg1);
+                }
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+            } break;
+            case CHECK_PENDING_VERIFICATION: {
+                final int verificationId = msg.arg1;
+                final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+
+                if ((state != null) && !state.isVerificationComplete()
+                        && !state.timeoutExtended()) {
+                    final VerificationParams params = state.getVerificationParams();
+                    final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+                    String errorMsg = "Verification timed out for " + originUri;
+                    Slog.i(TAG, errorMsg);
+
+                    final UserHandle user = params.getUser();
+                    if (getDefaultVerificationResponse(user)
+                            == PackageManager.VERIFICATION_ALLOW) {
+                        Slog.i(TAG, "Continuing with installation of " + originUri);
+                        state.setVerifierResponse(Binder.getCallingUid(),
+                                PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
+                        mPm.broadcastPackageVerified(verificationId, originUri,
+                                PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
+                                user);
+                    } else {
+                        mPm.broadcastPackageVerified(verificationId, originUri,
+                                PackageManager.VERIFICATION_REJECT, null,
+                                params.mDataLoaderType, user);
+                        params.setReturnCode(
+                                PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
+                        state.setVerifierResponse(Binder.getCallingUid(),
+                                PackageManager.VERIFICATION_REJECT);
+                    }
+
+                    if (state.areAllVerificationsComplete()) {
+                        mPm.mPendingVerification.remove(verificationId);
+                    }
+
+                    Trace.asyncTraceEnd(
+                            TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+                    params.handleVerificationFinished();
+
+                }
+                break;
+            }
+            case CHECK_PENDING_INTEGRITY_VERIFICATION: {
+                final int verificationId = msg.arg1;
+                final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+
+                if (state != null && !state.isIntegrityVerificationComplete()) {
+                    final VerificationParams params = state.getVerificationParams();
+                    final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+                    String errorMsg = "Integrity verification timed out for " + originUri;
+                    Slog.i(TAG, errorMsg);
+
+                    state.setIntegrityVerificationResult(
+                            getDefaultIntegrityVerificationResponse());
+
+                    if (getDefaultIntegrityVerificationResponse()
+                            == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
+                        Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
+                    } else {
+                        params.setReturnCode(
+                                PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+                                errorMsg);
+                    }
+
+                    if (state.areAllVerificationsComplete()) {
+                        mPm.mPendingVerification.remove(verificationId);
+                    }
+
+                    Trace.asyncTraceEnd(
+                            TRACE_TAG_PACKAGE_MANAGER,
+                            "integrity_verification",
+                            verificationId);
+
+                    params.handleIntegrityVerificationFinished();
+                }
+                break;
+            }
+            case PACKAGE_VERIFIED: {
+                final int verificationId = msg.arg1;
+
+                final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+                if (state == null) {
+                    Slog.w(TAG, "Verification with id " + verificationId
+                            + " not found."
+                            + " It may be invalid or overridden by integrity verification");
+                    break;
+                }
+
+                final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;
+
+                state.setVerifierResponse(response.callerUid, response.code);
+
+                if (state.isVerificationComplete()) {
+                    final VerificationParams params = state.getVerificationParams();
+                    final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+                    if (state.isInstallAllowed()) {
+                        mPm.broadcastPackageVerified(verificationId, originUri,
+                                response.code, null, params.mDataLoaderType, params.getUser());
+                    } else {
+                        params.setReturnCode(
+                                PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+                                "Install not allowed");
+                    }
+
+                    if (state.areAllVerificationsComplete()) {
+                        mPm.mPendingVerification.remove(verificationId);
+                    }
+
+                    Trace.asyncTraceEnd(
+                            TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+                    params.handleVerificationFinished();
+                }
+
+                break;
+            }
+            case INTEGRITY_VERIFICATION_COMPLETE: {
+                final int verificationId = msg.arg1;
+
+                final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+                if (state == null) {
+                    Slog.w(TAG, "Integrity verification with id " + verificationId
+                            + " not found. It may be invalid or overridden by verifier");
+                    break;
+                }
+
+                final int response = (Integer) msg.obj;
+                final VerificationParams params = state.getVerificationParams();
+                final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+                state.setIntegrityVerificationResult(response);
+
+                if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
+                    Slog.i(TAG, "Integrity check passed for " + originUri);
+                } else {
+                    params.setReturnCode(
+                            PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+                            "Integrity check failed for " + originUri);
+                }
+
+                if (state.areAllVerificationsComplete()) {
+                    mPm.mPendingVerification.remove(verificationId);
+                }
+
+                Trace.asyncTraceEnd(
+                        TRACE_TAG_PACKAGE_MANAGER,
+                        "integrity_verification",
+                        verificationId);
+
+                params.handleIntegrityVerificationFinished();
+                break;
+            }
+            case INSTANT_APP_RESOLUTION_PHASE_TWO: {
+                InstantAppResolver.doInstantAppResolutionPhaseTwo(mPm.mContext,
+                        mPm.mInstantAppResolverConnection,
+                        (InstantAppRequest) msg.obj,
+                        mPm.mInstantAppInstallerActivity,
+                        mPm.mHandler);
+                break;
+            }
+            case ENABLE_ROLLBACK_STATUS: {
+                final int enableRollbackToken = msg.arg1;
+                final int enableRollbackCode = msg.arg2;
+                final VerificationParams params =
+                        mPm.mPendingEnableRollback.get(enableRollbackToken);
+                if (params == null) {
+                    Slog.w(TAG, "Invalid rollback enabled token "
+                            + enableRollbackToken + " received");
+                    break;
+                }
+
+                mPm.mPendingEnableRollback.remove(enableRollbackToken);
+
+                if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
+                    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);
+                }
+
+                Trace.asyncTraceEnd(
+                        TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+
+                params.handleRollbackEnabled();
+                break;
+            }
+            case ENABLE_ROLLBACK_TIMEOUT: {
+                final int enableRollbackToken = msg.arg1;
+                final int sessionId = msg.arg2;
+                final VerificationParams params =
+                        mPm.mPendingEnableRollback.get(enableRollbackToken);
+                if (params != null) {
+                    final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+                    Slog.w(TAG, "Enable rollback timed out for " + originUri);
+                    mPm.mPendingEnableRollback.remove(enableRollbackToken);
+
+                    Slog.w(TAG, "Continuing with installation of " + originUri);
+                    Trace.asyncTraceEnd(
+                            TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+                    params.handleRollbackEnabled();
+                    Intent rollbackTimeoutIntent = new Intent(
+                            Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
+                    rollbackTimeoutIntent.putExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
+                            sessionId);
+                    rollbackTimeoutIntent.addFlags(
+                            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                    mPm.mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
+                            android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
+                }
+                break;
+            }
+            case DOMAIN_VERIFICATION: {
+                int messageCode = msg.arg1;
+                Object object = msg.obj;
+                mPm.mDomainVerificationManager.runMessage(messageCode, object);
+                break;
+            }
+            case SNAPSHOT_UNCORK: {
+                int corking = mPm.sSnapshotCorked.decrementAndGet();
+                if (TRACE_SNAPSHOTS && corking == 0) {
+                    Log.e(TAG, "snapshot: corking goes to zero in message handler");
+                }
+                break;
+            }
+        }
+    }
+
+    private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
+            boolean virtualPreload, boolean launchedForRestore, String installerPackage,
+            IPackageInstallObserver2 installObserver, int dataLoaderType) {
+        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 ? mPm.getPackageSetting(packageName) : null;
+        final boolean removedBeforeUpdate = (pkgSetting == null)
+                || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(
+                res.mPkg.getPath()));
+        if (succeeded && removedBeforeUpdate) {
+            Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+                    + "could be executed");
+            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.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
+            if (args != null) {
+                synchronized (mPm.mInstallLock) {
+                    args.doPostDeleteLI(true);
+                }
+            }
+            mPm.notifyInstallObserver(res, installObserver);
+            return;
+        }
+
+        if (succeeded) {
+            // Clear the uid cache after we installed a new package.
+            mPm.mPerUidReadTimeoutsCache = null;
+
+            // Send the removed broadcasts
+            if (res.mRemovedInfo != null) {
+                res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
+            }
+
+            final String installerPackageName =
+                    res.mInstallerPackageName != null
+                            ? res.mInstallerPackageName
+                            : res.mRemovedInfo != null
+                                    ? res.mRemovedInfo.mInstallerPackageName
+                                    : null;
+
+            synchronized (mPm.mLock) {
+                mPm.mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
+            }
+
+            // Determine the set of users who are adding this package for
+            // the first time vs. those who are seeing an update.
+            int[] firstUserIds = EMPTY_INT_ARRAY;
+            int[] firstInstantUserIds = EMPTY_INT_ARRAY;
+            int[] updateUserIds = EMPTY_INT_ARRAY;
+            int[] instantUserIds = EMPTY_INT_ARRAY;
+            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);
+                    } else {
+                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+                    }
+                    continue;
+                }
+                boolean isNew = true;
+                for (int origUser : res.mOrigUsers) {
+                    if (origUser == newUser) {
+                        isNew = false;
+                        break;
+                    }
+                }
+                if (isNew) {
+                    if (isInstantApp) {
+                        firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+                    } else {
+                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+                    }
+                } else {
+                    if (isInstantApp) {
+                        instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
+                    } else {
+                        updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
+                    }
+                }
+            }
+
+            // Send installed broadcasts if the package is not a static shared lib.
+            if (res.mPkg.getStaticSharedLibName() == null) {
+                mPm.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.mUid);
+                boolean isSystem = res.mPkg.isSystem();
+                mPm.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.mUid);
+                if (update) {
+                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
+                }
+                extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
+                // Send to all running apps.
+                final SparseArray<int[]> newBroadcastAllowList;
+
+                synchronized (mPm.mLock) {
+                    newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
+                            mPm.getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
+                            updateUserIds, mPm.mSettings.getPackagesLocked());
+                }
+                mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+                        extras, 0 /*flags*/,
+                        null /*targetPackage*/, null /*finishedReceiver*/,
+                        updateUserIds, instantUserIds, newBroadcastAllowList, null);
+                if (installerPackageName != null) {
+                    // Send to the installer, even if it's not running.
+                    mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+                            extras, 0 /*flags*/,
+                            installerPackageName, null /*finishedReceiver*/,
+                            updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
+                }
+                // if the required verifier is defined, but, is not the installer of record
+                // for the package, it gets notified
+                final boolean notifyVerifier = mPm.mRequiredVerifierPackage != null
+                        && !mPm.mRequiredVerifierPackage.equals(installerPackageName);
+                if (notifyVerifier) {
+                    mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+                            extras, 0 /*flags*/,
+                            mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
+                            updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
+                }
+                // If package installer is defined, notify package installer about new
+                // app installed
+                if (mPm.mRequiredInstallerPackage != null) {
+                    mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+                            extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
+                            mPm.mRequiredInstallerPackage, null /*finishedReceiver*/,
+                            firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
+                }
+
+                // Send replaced for users that don't see the package for the first time
+                if (update) {
+                    mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+                            packageName, extras, 0 /*flags*/,
+                            null /*targetPackage*/, null /*finishedReceiver*/,
+                            updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
+                            null);
+                    if (installerPackageName != null) {
+                        mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+                                extras, 0 /*flags*/,
+                                installerPackageName, null /*finishedReceiver*/,
+                                updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
+                    }
+                    if (notifyVerifier) {
+                        mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+                                extras, 0 /*flags*/,
+                                mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
+                                updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
+                    }
+                    mPm.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
+                            null /*package*/, null /*extras*/, 0 /*flags*/,
+                            packageName /*targetPackage*/,
+                            null /*finishedReceiver*/, updateUserIds, instantUserIds,
+                            null /*broadcastAllowList*/,
+                            mPm.getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
+                                    .toBundle());
+                } 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) {
+                        Slog.i(TAG, "Post-restore of " + packageName
+                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
+                    }
+                    mPm.sendFirstLaunchBroadcast(packageName, installerPackage,
+                            firstUserIds, firstInstantUserIds);
+                }
+
+                // Send broadcast package appeared if external for all users
+                if (res.mPkg.isExternalStorage()) {
+                    if (!update) {
+                        final StorageManager storage = mPm.mInjector.getSystemService(
+                                StorageManager.class);
+                        VolumeInfo volume =
+                                storage.findVolumeByUuid(
+                                        StorageManager.convert(
+                                                res.mPkg.getVolumeUuid()).toString());
+                        int packageExternalStorageType =
+                                PackageManagerService.getPackageExternalStorageType(volume,
+                                        res.mPkg.isExternalStorage());
+                        // If the package was installed externally, log it.
+                        if (packageExternalStorageType != StorageEnums.UNKNOWN) {
+                            FrameworkStatsLog.write(
+                                    FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+                                    packageExternalStorageType, packageName);
+                        }
+                    }
+                    if (DEBUG_INSTALL) {
+                        Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
+                    }
+                    final int[] uidArray = new int[]{res.mPkg.getUid()};
+                    ArrayList<String> pkgList = new ArrayList<>(1);
+                    pkgList.add(packageName);
+                    mPm.sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
+                }
+            } 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
+                    mPm.sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
+                            new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+                            pkg.getUid(), null);
+                }
+            }
+
+            // Work that needs to happen on first install within each user
+            if (firstUserIds != null && firstUserIds.length > 0) {
+                for (int userId : firstUserIds) {
+                    mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
+                            userId);
+                }
+            }
+
+            if (allNewUsers && !update) {
+                mPm.notifyPackageAdded(packageName, res.mUid);
+            } else {
+                mPm.notifyPackageChanged(packageName, res.mUid);
+            }
+
+            // Log current value of "unknown sources" setting
+            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
+                    getUnknownSourcesSettings());
+
+            // Remove the replaced package's older resources safely now
+            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
+                    // they may still be in use by the running application. This mitigates problems
+                    // in cases where resources or code is loaded by a new Activity before
+                    // ApplicationInfo changes have propagated to all application threads.
+                    mPm.scheduleDeferredNoKillPostDelete(args);
+                } else {
+                    synchronized (mPm.mInstallLock) {
+                        args.doPostDeleteLI(true);
+                    }
+                }
+            } else {
+                // Force a gc to clear up things. Ask for a background one, it's fine to go on
+                // and not block here.
+                VMRuntime.getRuntime().requestConcurrentGC();
+            }
+
+            // Notify DexManager that the package was installed for new users.
+            // The updated users should already be indexed and the package code paths
+            // should not change.
+            // Don't notify the manager for ephemeral apps as they are not expected to
+            // survive long enough to benefit of background optimizations.
+            for (int userId : firstUserIds) {
+                PackageInfo info = mPm.getPackageInfo(packageName, /*flags*/ 0, userId);
+                // There's a race currently where some install events may interleave with an
+                // uninstall. This can lead to package info being null (b/36642664).
+                if (info != null) {
+                    mPm.getDexManager().notifyPackageInstalled(info, userId);
+                }
+            }
+        }
+
+        final boolean deferInstallObserver = succeeded && update && !killApp;
+        if (deferInstallObserver) {
+            mPm.scheduleDeferredNoKillInstallObserver(res, installObserver);
+        } else {
+            mPm.notifyInstallObserver(res, installObserver);
+        }
+    }
+
+    /**
+     * Get the default verification agent response code.
+     *
+     * @return default verification response code
+     */
+    private int getDefaultVerificationResponse(UserHandle user) {
+        if (mPm.mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS,
+                user.getIdentifier())) {
+            return PackageManager.VERIFICATION_REJECT;
+        }
+        return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(),
+                android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+                DEFAULT_VERIFICATION_RESPONSE);
+    }
+
+    /**
+     * Get the default integrity verification response code.
+     */
+    private int getDefaultIntegrityVerificationResponse() {
+        // 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 PackageManager.VERIFICATION_REJECT;
+    }
+
+    /**
+     * Get the "allow unknown sources" setting.
+     *
+     * @return the current "allow unknown sources" setting
+     */
+    private int getUnknownSourcesSettings() {
+        return android.provider.Settings.Secure.getIntForUser(mPm.mContext.getContentResolver(),
+                android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
+                -1, UserHandle.USER_SYSTEM);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
index afe6bb2..d0ca9d84 100644
--- a/services/core/java/com/android/server/pm/PackageInstalledInfo.java
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -18,7 +18,6 @@
 
 import static com.android.server.pm.PackageManagerService.TAG;
 
-import android.content.pm.PackageParser;
 import android.util.ExceptionUtils;
 import android.util.Slog;
 
@@ -59,12 +58,6 @@
         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));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index fe419a6..b34a3a2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -261,6 +261,10 @@
                 new Lifecycle(context, this));
     }
 
+    StagingManager getStagingManager() {
+        return mStagingManager;
+    }
+
     boolean okToSendBroadcasts()  {
         return mOkToSendBroadcasts;
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index fdbcf85..08c95c2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -144,6 +144,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.security.VerityUtils;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -2112,6 +2113,11 @@
         Slog.e(TAG, "Failed to verify session " + sessionId + " [" + msgWithErrorCode + "]");
         // Session is sealed and committed but could not be verified, we need to destroy it.
         destroyInternal();
+        if (isMultiPackage()) {
+            for (PackageInstallerSession childSession : getChildSessions()) {
+                childSession.destroyInternal();
+            }
+        }
         if (isStaged()) {
             mStagedSession.setSessionFailed(
                     SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
@@ -2615,11 +2621,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 {
@@ -2639,6 +2647,7 @@
                 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
@@ -2975,6 +2984,8 @@
 
         // Verify that all staged packages are internally consistent
         final ArraySet<String> stagedSplits = new ArraySet<>();
+        final ArraySet<String> stagedSplitTypes = new ArraySet<>();
+        final ArraySet<String> requiredSplitTypes = new ArraySet<>();
         final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>();
         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
         for (File addedFile : addedFiles) {
@@ -3030,6 +3041,10 @@
             } else {
                 splitApks.put(apk.getSplitName(), apk);
             }
+
+            // Collect the requiredSplitTypes and staged splitTypes
+            CollectionUtils.addAll(requiredSplitTypes, apk.getRequiredSplitTypes());
+            CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes());
         }
 
         if (removeSplitList.size() > 0) {
@@ -3084,7 +3099,8 @@
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Full install must include a base package");
             }
-            if (baseApk.isSplitRequired() && stagedSplits.size() <= 1) {
+            if (baseApk.isSplitRequired() && (stagedSplits.size() <= 1
+                    || !stagedSplitTypes.containsAll(requiredSplitTypes))) {
                 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
                         "Missing split for " + mPackageName);
             }
@@ -3122,6 +3138,8 @@
             if (mResolvedBaseFile == null) {
                 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 inheritFileLocked(mResolvedBaseFile);
+                // Collect the requiredSplitTypes from base
+                CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
             }
 
             // Inherit splits if not overridden.
@@ -3132,6 +3150,10 @@
                     final boolean splitRemoved = removeSplitList.contains(splitName);
                     if (!stagedSplits.contains(splitName) && !splitRemoved) {
                         inheritFileLocked(splitFile);
+                        // Collect the requiredSplitTypes and staged splitTypes from splits
+                        CollectionUtils.addAll(requiredSplitTypes,
+                                existing.getRequiredSplitTypes()[i]);
+                        CollectionUtils.addAll(stagedSplitTypes, existing.getSplitTypes()[i]);
                     }
                 }
             }
@@ -3213,7 +3235,8 @@
                 final boolean allSplitsRemoved = (existingSplits == removeSplitList.size());
                 final boolean onlyBaseFileStaged = (stagedSplits.size() == 1
                         && stagedSplits.contains(null));
-                if (allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged)) {
+                if ((allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged))
+                        || !stagedSplitTypes.containsAll(requiredSplitTypes)) {
                     throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
                             "Missing split for " + mPackageName);
                 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c9e4829..098a9b6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -39,11 +39,9 @@
 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_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_SUCCEEDED;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -74,7 +72,6 @@
 import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
 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.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.incremental.IncrementalManager.isIncrementalPath;
@@ -86,10 +83,7 @@
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
-import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
-import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
-import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
 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;
@@ -98,13 +92,10 @@
 import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
-import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
 import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
 import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
-import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
 import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
-import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
 import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
 import static com.android.server.pm.parsing.PackageInfoUtils.checkUseInstalledOrHidden;
 
@@ -163,6 +154,7 @@
 import android.content.pm.IPackageManagerNative;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IStagedApexObserver;
 import android.content.pm.IncrementalStatesInfo;
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.InstantAppInfo;
@@ -174,9 +166,9 @@
 import android.content.pm.ModuleInfo;
 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.PackageManager.ComponentEnabledSetting;
 import android.content.pm.PackageManager.ComponentType;
 import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
 import android.content.pm.PackageManager.ModuleInfoFlags;
@@ -186,7 +178,6 @@
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
 import android.content.pm.PackagePartitions;
-import android.content.pm.PackagePartitions.SystemPartition;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
 import android.content.pm.ParceledListSlice;
@@ -200,8 +191,8 @@
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
 import android.content.pm.SigningDetails;
-import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.SigningInfo;
+import android.content.pm.StagedApexInfo;
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.TestUtilityService;
 import android.content.pm.UserInfo;
@@ -272,7 +263,6 @@
 import android.security.KeyStore;
 import android.service.pm.PackageServiceDumpProto;
 import android.stats.storage.StorageEnums;
-import android.system.ErrnoException;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -289,6 +279,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;
@@ -307,13 +298,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.F2fsUtils;
-import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.content.om.OverlayConfig;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.AttributeCache;
-import com.android.internal.security.VerityUtils;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
@@ -327,6 +316,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;
@@ -360,6 +350,10 @@
 import com.android.server.pm.permission.LegacyPermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.PackageState;
+import com.android.server.pm.pkg.PackageStateImpl;
+import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.DomainVerificationUtils;
@@ -382,7 +376,6 @@
 
 import dalvik.system.VMRuntime;
 
-import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 import libcore.util.HexEncoding;
 
@@ -403,7 +396,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.nio.charset.StandardCharsets;
-import java.security.DigestException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
@@ -484,7 +476,7 @@
     static final boolean DEBUG_PREFERRED = false;
     static final boolean DEBUG_UPGRADE = false;
     static final boolean DEBUG_DOMAIN_VERIFICATION = false;
-    private static final boolean DEBUG_BACKUP = false;
+    static final boolean DEBUG_BACKUP = false;
     public static final boolean DEBUG_INSTALL = false;
     public static final boolean DEBUG_REMOVE = false;
     private static final boolean DEBUG_BROADCASTS = false;
@@ -617,7 +609,7 @@
     /** Suffix of stub packages on the system partition */
     public final static String STUB_SUFFIX = "-Stub";
 
-    private static final int[] EMPTY_INT_ARRAY = new int[0];
+    static final int[] EMPTY_INT_ARRAY = new int[0];
 
     /**
      * Timeout (in milliseconds) after which the watchdog should declare that
@@ -669,7 +661,7 @@
      * This can be either PackageManager.VERIFICATION_ALLOW or
      * PackageManager.VERIFICATION_REJECT.
      */
-    private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
+    static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
 
     /**
      * Adding an installer package name to a package that does not have one set requires the
@@ -701,6 +693,20 @@
     @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";
 
     static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -750,7 +756,7 @@
 
     final Handler mHandler;
 
-    private final ProcessLoggingHandler mProcessLoggingHandler;
+    final ProcessLoggingHandler mProcessLoggingHandler;
 
     private final boolean mEnableFreeCacheV2;
 
@@ -819,7 +825,7 @@
      * find updated user-installed versions. Keys are package name, values
      * are package location.
      */
-    final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+    final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
 
     /**
      * Tracks existing packages prior to receiving an OTA. Keys are package name.
@@ -838,7 +844,7 @@
      * @see Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL
      * @see #systemReady()
      */
-    private @Nullable List<File> mReleaseOnSystemReady;
+    @Nullable List<File> mReleaseOnSystemReady;
 
     /**
      * Whether or not system app permissions should be promoted from install to runtime.
@@ -881,7 +887,7 @@
     final ArrayMap<String, FeatureInfo> mAvailableFeatures;
 
     @Watched
-    private final InstantAppRegistry mInstantAppRegistry;
+    final InstantAppRegistry mInstantAppRegistry;
 
     @GuardedBy("mLock")
     int mChangedPackagesSequenceNumber;
@@ -924,7 +930,7 @@
         new ArrayList<>();
 
     // Cached parsed flag value. Invalidated on each flag change.
-    private PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
+    PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
 
     private static final PerUidReadTimeouts[] EMPTY_PER_UID_READ_TIMEOUTS_ARRAY = {};
 
@@ -1422,7 +1428,7 @@
     boolean mResolverReplaced = false;
 
     @NonNull
-    private final DomainVerificationManagerInternal mDomainVerificationManager;
+    final DomainVerificationManagerInternal mDomainVerificationManager;
 
     /** The service connection to the ephemeral resolver */
     final InstantAppResolverConnection mInstantAppResolverConnection;
@@ -1566,7 +1572,7 @@
     final UserManagerService mUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
-    private final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
+    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
@@ -1850,6 +1856,9 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected interface Computer {
 
+        @Nullable
+        PackageState getPackageState(@NonNull String packageName);
+
         /**
          * Every method must be annotated.
          */
@@ -2031,6 +2040,13 @@
         boolean filterAppAccess(int uid, int callingUid);
         @LiveImplementation(override = LiveImplementation.MANDATORY)
         void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
+        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+        FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
+                String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
+        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+        ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
+                List<ResolveInfo> query, boolean debug, int userId);
     }
 
     /**
@@ -2160,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();
                 }
@@ -2172,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
@@ -2216,35 +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);
                     }
                 }
-
-                return applyPostResolutionFilter(
-                        list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
-                        resolveForStart,
-                        userId, intent);
+            } 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);
         }
 
@@ -2267,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
@@ -2308,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,
@@ -2812,7 +2855,24 @@
             }
             allHomeCandidates.addAll(resolveInfos);
 
-            final String packageName = mDefaultAppProvider.getDefaultHome(userId);
+            String packageName = mDefaultAppProvider.getDefaultHome(userId);
+            if (packageName == null) {
+                // Role changes are not and cannot be atomic because its implementation lives inside
+                // a system app, so when the home role changes, there is a window when the previous
+                // role holder is removed and the new role holder is granted the preferred activity,
+                // but hasn't become the role holder yet. However, this case may be easily hit
+                // because the preferred activity change triggers a broadcast and receivers may try
+                // to get the default home activity there. So we need to fix it for this time
+                // window, and an easy workaround is to fallback to the current preferred activity.
+                final int appId = UserHandle.getAppId(Binder.getCallingUid());
+                final boolean filtered = appId >= Process.FIRST_APPLICATION_UID;
+                FindPreferredActivityBodyResult result = findPreferredActivityInternal(
+                        intent, null, 0, resolveInfos, true, false, false, userId, filtered);
+                ResolveInfo preferredResolveInfo =  result.mPreferredResolveInfo;
+                if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) {
+                    packageName = preferredResolveInfo.activityInfo.packageName;
+                }
+            }
             if (packageName == null) {
                 return null;
             }
@@ -3361,6 +3421,16 @@
             return mSettings.getPackageLPr(packageName);
         }
 
+        @Nullable
+        @Override
+        public PackageState getPackageState(@NonNull String packageName) {
+            int callingUid = Binder.getCallingUid();
+            packageName = resolveInternalPackageNameInternalLocked(
+                    packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
+            PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+            return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
+        }
+
         public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
             final int callingUid = Binder.getCallingUid();
             if (getInstantAppPackageName(callingUid) != null) {
@@ -4564,8 +4634,14 @@
 
         public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
             final String packageName = dumpState.getTargetPackageName();
+            final PackageSetting setting = mSettings.getPackageLPr(packageName);
             final boolean checkin = dumpState.isCheckIn();
 
+            // Return if the package doesn't exist.
+            if (packageName != null && setting == null) {
+                return;
+            }
+
             switch (type) {
                 case DumpState.DUMP_VERSION:
                 {
@@ -4658,8 +4734,7 @@
 
                 case DumpState.DUMP_QUERIES:
                 {
-                    final PackageSetting setting = mSettings.getPackageLPr(packageName);
-                    Integer filteringAppId = setting == null ? null : setting.appId;
+                    final Integer filteringAppId = setting == null ? null : setting.appId;
                     mAppsFilter.dumpQueries(
                             pw, filteringAppId, dumpState, mUserManager.getUserIds(),
                             this::getPackagesForUidInternalBody);
@@ -4670,8 +4745,9 @@
                 {
                     final android.util.IndentingPrintWriter writer =
                             new android.util.IndentingPrintWriter(pw);
-                    if (dumpState.onTitlePrinted()) pw.println();
-
+                    if (dumpState.onTitlePrinted()) {
+                        pw.println();
+                    }
                     writer.println("Domain verification status:");
                     writer.increaseIndent();
                     try {
@@ -4688,18 +4764,14 @@
                 case DumpState.DUMP_DEXOPT:
                 {
                     final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-                    ipw.println();
+                    if (dumpState.onTitlePrinted()) {
+                        pw.println();
+                    }
                     ipw.println("Dexopt state:");
                     ipw.increaseIndent();
                     Collection<PackageSetting> pkgSettings;
-                    if (packageName != null) {
-                        PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
-                        if (targetPkgSetting != null) {
-                            pkgSettings = Collections.singletonList(targetPkgSetting);
-                        } else {
-                            ipw.println("Unable to find package: " + packageName);
-                            return;
-                        }
+                    if (setting != null) {
+                        pkgSettings = Collections.singletonList(setting);
                     } else {
                         pkgSettings = mSettings.getPackagesLocked().values();
                     }
@@ -4709,10 +4781,12 @@
                         if (pkg == null) {
                             continue;
                         }
-                        ipw.println("[" + pkgSetting.name + "]");
+                        final String pkgName = pkg.getPackageName();
+                        ipw.println("[" + pkgName + "]");
                         ipw.increaseIndent();
+
                         mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
-                                mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
+                                mDexManager.getPackageUseInfoOrDefault(pkgName));
                         ipw.decreaseIndent();
                     }
                     break;
@@ -4721,28 +4795,29 @@
                 case DumpState.DUMP_COMPILER_STATS:
                 {
                     final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-                    ipw.println();
+                    if (dumpState.onTitlePrinted()) {
+                        pw.println();
+                    }
                     ipw.println("Compiler stats:");
                     ipw.increaseIndent();
-                    Collection<AndroidPackage> packages;
-                    if (packageName != null) {
-                        AndroidPackage targetPackage = mPackages.get(packageName);
-                        if (targetPackage != null) {
-                            packages = Collections.singletonList(targetPackage);
-                        } else {
-                            ipw.println("Unable to find package: " + packageName);
-                            return;
-                        }
+                    Collection<PackageSetting> pkgSettings;
+                    if (setting != null) {
+                        pkgSettings = Collections.singletonList(setting);
                     } else {
-                        packages = mPackages.values();
+                        pkgSettings = mSettings.getPackagesLocked().values();
                     }
 
-                    for (AndroidPackage pkg : packages) {
+                    for (PackageSetting pkgSetting : pkgSettings) {
+                        final AndroidPackage pkg = pkgSetting.getPkg();
+                        if (pkg == null) {
+                            continue;
+                        }
                         final String pkgName = pkg.getPackageName();
                         ipw.println("[" + pkgName + "]");
                         ipw.increaseIndent();
 
-                        CompilerStats.PackageStats stats = mCompilerStats.getPackageStats(pkgName);
+                        final CompilerStats.PackageStats stats =
+                                mCompilerStats.getPackageStats(pkgName);
                         if (stats == null) {
                             ipw.println("(No recorded stats)");
                         } else {
@@ -4754,6 +4829,284 @@
                 }
             } // switch
         }
+
+        // The body of findPreferredActivity.
+        protected FindPreferredActivityBodyResult findPreferredActivityBody(
+                Intent intent, String resolvedType, int flags,
+                List<ResolveInfo> query, boolean always,
+                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+                int callingUid, boolean isDeviceProvisioned) {
+            FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult();
+
+            flags = updateFlagsForResolve(
+                    flags, userId, callingUid, false /*includeInstantApps*/,
+                    isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+                            resolvedType, flags));
+            intent = updateIntentForResolve(intent);
+
+            // Try to find a matching persistent preferred activity.
+            result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+                    resolvedType, flags, query, debug, userId);
+
+            // If a persistent preferred activity matched, use it.
+            if (result.mPreferredResolveInfo != null) {
+                return result;
+            }
+
+            PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
+            // Get the list of preferred activities that handle the intent
+            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
+            List<PreferredActivity> prefs = pir != null
+                    ? pir.queryIntent(intent, resolvedType,
+                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+                            userId)
+                    : null;
+            if (prefs != null && prefs.size() > 0) {
+
+                // First figure out how good the original match set is.
+                // We will only allow preferred activities that came
+                // from the same match quality.
+                int match = 0;
+
+                if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
+
+                final int N = query.size();
+                for (int j = 0; j < N; j++) {
+                    final ResolveInfo ri = query.get(j);
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Match for " + ri.activityInfo
+                                + ": 0x" + Integer.toHexString(match));
+                    }
+                    if (ri.match > match) {
+                        match = ri.match;
+                    }
+                }
+
+                if (DEBUG_PREFERRED || debug) {
+                    Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match));
+                }
+                match &= IntentFilter.MATCH_CATEGORY_MASK;
+                final int M = prefs.size();
+                for (int i = 0; i < M; i++) {
+                    final PreferredActivity pa = prefs.get(i);
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Checking PreferredActivity ds="
+                                + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
+                                + "\n  component=" + pa.mPref.mComponent);
+                        pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                    }
+                    if (pa.mPref.mMatch != match) {
+                        if (DEBUG_PREFERRED || debug) {
+                            Slog.v(TAG, "Skipping bad match "
+                                    + Integer.toHexString(pa.mPref.mMatch));
+                        }
+                        continue;
+                    }
+                    // If it's not an "always" type preferred activity and that's what we're
+                    // looking for, skip it.
+                    if (always && !pa.mPref.mAlways) {
+                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
+                        continue;
+                    }
+                    final ActivityInfo ai = getActivityInfo(
+                            pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+                                    | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                            userId);
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Found preferred activity:");
+                        if (ai != null) {
+                            ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                        } else {
+                            Slog.v(TAG, "  null");
+                        }
+                    }
+                    final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
+                            && !isDeviceProvisioned;
+                    final boolean allowSetMutation = !excludeSetupWizardHomeActivity
+                            && !queryMayBeFiltered;
+                    if (ai == null) {
+                        // Do not remove launcher's preferred activity during SetupWizard
+                        // due to it may not install yet
+                        if (!allowSetMutation) {
+                            continue;
+                        }
+
+                        // This previously registered preferred activity
+                        // component is no longer known.  Most likely an update
+                        // to the app was installed and in the new version this
+                        // component no longer exists.  Clean it up by removing
+                        // it from the preferred activities list, and skip it.
+                        Slog.w(TAG, "Removing dangling preferred activity: "
+                                + pa.mPref.mComponent);
+                        pir.removeFilter(pa);
+                        result.mChanged = true;
+                        continue;
+                    }
+                    for (int j = 0; j < N; j++) {
+                        final ResolveInfo ri = query.get(j);
+                        if (!ri.activityInfo.applicationInfo.packageName
+                                .equals(ai.applicationInfo.packageName)) {
+                            continue;
+                        }
+                        if (!ri.activityInfo.name.equals(ai.name)) {
+                            continue;
+                        }
+
+                        if (removeMatches && allowSetMutation) {
+                            pir.removeFilter(pa);
+                            result.mChanged = true;
+                            if (DEBUG_PREFERRED) {
+                                Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
+                            }
+                            break;
+                        }
+
+                        // Okay we found a previously set preferred or last chosen app.
+                        // If the result set is different from when this
+                        // was created, and is not a subset of the preferred set, we need to
+                        // clear it and re-ask the user their preference, if we're looking for
+                        // an "always" type entry.
+
+                        if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
+                            if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
+                                if (allowSetMutation) {
+                                    // some components of the set are no longer present in
+                                    // the query, but the preferred activity can still be reused
+                                    if (DEBUG_PREFERRED) {
+                                        Slog.i(TAG, "Result set changed, but PreferredActivity"
+                                                + " is still valid as only non-preferred"
+                                                + " components were removed for " + intent
+                                                + " type " + resolvedType);
+                                    }
+                                    // remove obsolete components and re-add the up-to-date
+                                    // filter
+                                    PreferredActivity freshPa = new PreferredActivity(pa,
+                                            pa.mPref.mMatch,
+                                            pa.mPref.discardObsoleteComponents(query),
+                                            pa.mPref.mComponent,
+                                            pa.mPref.mAlways);
+                                    pir.removeFilter(pa);
+                                    pir.addFilter(freshPa);
+                                    result.mChanged = true;
+                                } else {
+                                    if (DEBUG_PREFERRED) {
+                                        Slog.i(TAG, "Do not remove preferred activity");
+                                    }
+                                }
+                            } else {
+                                if (allowSetMutation) {
+                                    Slog.i(TAG,
+                                            "Result set changed, dropping preferred activity "
+                                                    + "for " + intent + " type "
+                                                    + resolvedType);
+                                    if (DEBUG_PREFERRED) {
+                                        Slog.v(TAG,
+                                                "Removing preferred activity since set changed "
+                                                        + pa.mPref.mComponent);
+                                    }
+                                    pir.removeFilter(pa);
+                                    // Re-add the filter as a "last chosen" entry (!always)
+                                    PreferredActivity lastChosen = new PreferredActivity(
+                                            pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
+                                            false);
+                                    pir.addFilter(lastChosen);
+                                    result.mChanged = true;
+                                }
+                                result.mPreferredResolveInfo = null;
+                                return result;
+                            }
+                        }
+
+                        // Yay! Either the set matched or we're looking for the last chosen
+                        if (DEBUG_PREFERRED || debug) {
+                            Slog.v(TAG, "Returning preferred activity: "
+                                    + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+                        }
+                        result.mPreferredResolveInfo = ri;
+                        return result;
+                    }
+                }
+            }
+            return result;
+        }
+
+        public final FindPreferredActivityBodyResult findPreferredActivityInternal(
+                Intent intent, String resolvedType, int flags,
+                List<ResolveInfo> query, boolean always,
+                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+
+            final int callingUid = Binder.getCallingUid();
+            // Do NOT hold the packages lock; this calls up into the settings provider which
+            // could cause a deadlock.
+            final boolean isDeviceProvisioned =
+                    android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+                            android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
+            // Find the preferred activity - the lock is held inside the method.
+            return findPreferredActivityBody(
+                    intent, resolvedType, flags, query, always, removeMatches, debug,
+                    userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
+        }
+
+        public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+                String resolvedType,
+                int flags, List<ResolveInfo> query, boolean debug, int userId) {
+            final int N = query.size();
+            PersistentPreferredIntentResolver ppir =
+                    mSettings.getPersistentPreferredActivities(userId);
+            // Get the list of persistent preferred activities that handle the intent
+            if (DEBUG_PREFERRED || debug) {
+                Slog.v(TAG, "Looking for persistent preferred activities...");
+            }
+            List<PersistentPreferredActivity> pprefs = ppir != null
+                    ? ppir.queryIntent(intent, resolvedType,
+                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+                            userId)
+                    : null;
+            if (pprefs != null && pprefs.size() > 0) {
+                final int M = pprefs.size();
+                for (int i = 0; i < M; i++) {
+                    final PersistentPreferredActivity ppa = pprefs.get(i);
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+                                + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
+                                + "\n  component=" + ppa.mComponent);
+                        ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                    }
+                    final ActivityInfo ai = getActivityInfo(ppa.mComponent,
+                            flags | MATCH_DISABLED_COMPONENTS, userId);
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Found persistent preferred activity:");
+                        if (ai != null) {
+                            ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                        } else {
+                            Slog.v(TAG, "  null");
+                        }
+                    }
+                    if (ai == null) {
+                        // This previously registered persistent preferred activity
+                        // component is no longer known. Ignore it and do NOT remove it.
+                        continue;
+                    }
+                    for (int j = 0; j < N; j++) {
+                        final ResolveInfo ri = query.get(j);
+                        if (!ri.activityInfo.applicationInfo.packageName
+                                .equals(ai.applicationInfo.packageName)) {
+                            continue;
+                        }
+                        if (!ri.activityInfo.name.equals(ai.name)) {
+                            continue;
+                        }
+                        //  Found a persistent preference that can handle the intent.
+                        if (DEBUG_PREFERRED || debug) {
+                            Slog.v(TAG, "Returning persistent preferred activity: "
+                                    + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+                        }
+                        return ri;
+                    }
+                }
+            }
+            return null;
+        }
     }
 
     /**
@@ -4844,6 +5197,14 @@
                 return super.getPackageSettingInternal(packageName, callingUid);
             }
         }
+
+        @Nullable
+        public final PackageState getPackageState(@NonNull String packageName) {
+            synchronized (mLock) {
+                return super.getPackageState(packageName);
+            }
+        }
+
         public final ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
                 int callingUid) {
             synchronized (mLock) {
@@ -4918,6 +5279,16 @@
                 super.dump(type, fd, pw, dumpState);
             }
         }
+        public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent,
+                String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+                int callingUid, boolean isDeviceProvisioned) {
+            synchronized (mLock) {
+                return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
+                        removeMatches, debug, userId, queryMayBeFiltered, callingUid,
+                        isDeviceProvisioned);
+            }
+        }
     }
 
     /**
@@ -5169,6 +5540,17 @@
                 current.release();
             }
         }
+
+        @Nullable
+        public final PackageState getPackageState(@NonNull String packageName) {
+            ThreadComputer current = live();
+            try {
+                return current.mComputer.getPackageState(packageName);
+            } finally {
+                current.release();
+            }
+        }
+
         public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
             ThreadComputer current = snapshot();
             try {
@@ -5493,6 +5875,28 @@
                 current.release();
             }
         }
+        public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
+                String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+            ThreadComputer current = live();
+            try {
+                return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
+                        query, always, removeMatches, debug, userId, queryMayBeFiltered);
+            } finally {
+                current.release();
+            }
+        }
+        public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+                String resolvedType, int flags, List<ResolveInfo> query, boolean debug,
+                int userId) {
+            ThreadComputer current = live();
+            try {
+                return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
+                        flags, query, debug, userId);
+            } finally {
+                current.release();
+            }
+        }
     }
 
 
@@ -5516,7 +5920,7 @@
     // 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 final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
+    static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
 
     /**
      * This class records the Computer being used by a thread and the Computer's reference
@@ -5544,10 +5948,8 @@
             }
         }
     }
-    private static final 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
@@ -5692,665 +6094,8 @@
         onChange(null);
     }
 
-    class PackageHandler extends Handler {
-
-        PackageHandler(Looper looper) {
-            super(looper);
-        }
-
-        public void handleMessage(Message msg) {
-            try {
-                doHandleMessage(msg);
-            } finally {
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            }
-        }
-
-        void doHandleMessage(Message msg) {
-            switch (msg.what) {
-                case INIT_COPY: {
-                    HandlerParams params = (HandlerParams) msg.obj;
-                    if (params != null) {
-                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
-                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                System.identityHashCode(params));
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
-                        params.startCopy();
-                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                    }
-                    break;
-                }
-                case SEND_PENDING_BROADCAST: {
-                    String[] packages;
-                    ArrayList<String>[] components;
-                    int size = 0;
-                    int[] uids;
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-                    synchronized (mLock) {
-                        size = mPendingBroadcasts.size();
-                        if (size <= 0) {
-                            // Nothing to be done. Just return
-                            return;
-                        }
-                        packages = new String[size];
-                        components = new ArrayList[size];
-                        uids = new int[size];
-                        int i = 0;  // filling out the above arrays
-
-                        for (int n = 0; n < mPendingBroadcasts.userIdCount(); n++) {
-                            final int packageUserId = mPendingBroadcasts.userIdAt(n);
-                            final ArrayMap<String, ArrayList<String>> componentsToBroadcast =
-                                    mPendingBroadcasts.packagesForUserId(packageUserId);
-                            final int numComponents = componentsToBroadcast.size();
-                            for (int index = 0; i < size && index < numComponents; index++) {
-                                packages[i] = componentsToBroadcast.keyAt(index);
-                                components[i] = componentsToBroadcast.valueAt(index);
-                                final PackageSetting ps = mSettings.getPackageLPr(packages[i]);
-                                uids[i] = (ps != null)
-                                        ? UserHandle.getUid(packageUserId, ps.appId)
-                                        : -1;
-                                i++;
-                            }
-                        }
-                        size = i;
-                        mPendingBroadcasts.clear();
-                    }
-                    // Send broadcasts
-                    for (int i = 0; i < size; i++) {
-                        sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
-                                components[i], uids[i], null /* reason */);
-                    }
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                    break;
-                }
-                case POST_INSTALL: {
-                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
-
-                    PostInstallData data = mRunningInstalls.get(msg.arg1);
-                    final boolean didRestore = (msg.arg2 != 0);
-                    mRunningInstalls.delete(msg.arg1);
-
-                    if (data != null && data.res.mFreezer != null) {
-                        data.res.mFreezer.close();
-                    }
-
-                    if (data != null && data.mPostInstallRunnable != null) {
-                        data.mPostInstallRunnable.run();
-                    } else if (data != null && data.args != null) {
-                        InstallArgs args = data.args;
-                        PackageInstalledInfo parentRes = data.res;
-
-                        final boolean killApp = (args.mInstallFlags
-                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
-                        final boolean virtualPreload = ((args.mInstallFlags
-                                & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
-
-                        handlePackagePostInstall(parentRes, killApp, virtualPreload,
-                                didRestore, args.mInstallSource.installerPackageName,
-                                args.mObserver, args.mDataLoaderType);
-
-                        // Log tracing if needed
-                        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
-                        Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
-                    }
-
-                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
-                } break;
-                case DEFERRED_NO_KILL_POST_DELETE: {
-                    synchronized (mInstallLock) {
-                        InstallArgs args = (InstallArgs) msg.obj;
-                        if (args != null) {
-                            args.doPostDeleteLI(true);
-                        }
-                    }
-                } break;
-                case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
-                    String packageName = (String) msg.obj;
-                    if (packageName != null) {
-                        notifyInstallObserver(packageName);
-                    }
-                } break;
-                case WRITE_SETTINGS: {
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-                    synchronized (mLock) {
-                        removeMessages(WRITE_SETTINGS);
-                        removeMessages(WRITE_PACKAGE_RESTRICTIONS);
-                        writeSettingsLPrTEMP();
-                        mDirtyUsers.clear();
-                    }
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                } break;
-                case WRITE_PACKAGE_RESTRICTIONS: {
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-                    synchronized (mLock) {
-                        removeMessages(WRITE_PACKAGE_RESTRICTIONS);
-                        for (int userId : mDirtyUsers) {
-                            mSettings.writePackageRestrictionsLPr(userId);
-                        }
-                        mDirtyUsers.clear();
-                    }
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                } break;
-                case WRITE_PACKAGE_LIST: {
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-                    synchronized (mLock) {
-                        removeMessages(WRITE_PACKAGE_LIST);
-                        mSettings.writePackageListLPr(msg.arg1);
-                    }
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                } break;
-                case CHECK_PENDING_VERIFICATION: {
-                    final int verificationId = msg.arg1;
-                    final PackageVerificationState state = mPendingVerification.get(verificationId);
-
-                    if ((state != null) && !state.isVerificationComplete()
-                            && !state.timeoutExtended()) {
-                        final VerificationParams params = state.getVerificationParams();
-                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
-                        String errorMsg = "Verification timed out for " + originUri;
-                        Slog.i(TAG, errorMsg);
-
-                        final UserHandle user = params.getUser();
-                        if (getDefaultVerificationResponse(user)
-                                == PackageManager.VERIFICATION_ALLOW) {
-                            Slog.i(TAG, "Continuing with installation of " + originUri);
-                            state.setVerifierResponse(Binder.getCallingUid(),
-                                    PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
-                            broadcastPackageVerified(verificationId, originUri,
-                                    PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
-                                    user);
-                        } else {
-                            broadcastPackageVerified(verificationId, originUri,
-                                    PackageManager.VERIFICATION_REJECT, null,
-                                    params.mDataLoaderType, user);
-                            params.setReturnCode(
-                                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
-                            state.setVerifierResponse(Binder.getCallingUid(),
-                                    PackageManager.VERIFICATION_REJECT);
-                        }
-
-                        if (state.areAllVerificationsComplete()) {
-                            mPendingVerification.remove(verificationId);
-                        }
-
-                        Trace.asyncTraceEnd(
-                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
-                        params.handleVerificationFinished();
-
-                    }
-                    break;
-                }
-                case CHECK_PENDING_INTEGRITY_VERIFICATION: {
-                    final int verificationId = msg.arg1;
-                    final PackageVerificationState state = mPendingVerification.get(verificationId);
-
-                    if (state != null && !state.isIntegrityVerificationComplete()) {
-                        final VerificationParams params = state.getVerificationParams();
-                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
-                        String errorMsg = "Integrity verification timed out for " + originUri;
-                        Slog.i(TAG, errorMsg);
-
-                        state.setIntegrityVerificationResult(
-                                getDefaultIntegrityVerificationResponse());
-
-                        if (getDefaultIntegrityVerificationResponse()
-                                == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
-                            Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
-                        } else {
-                            params.setReturnCode(
-                                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
-                                    errorMsg);
-                        }
-
-                        if (state.areAllVerificationsComplete()) {
-                            mPendingVerification.remove(verificationId);
-                        }
-
-                        Trace.asyncTraceEnd(
-                                TRACE_TAG_PACKAGE_MANAGER,
-                                "integrity_verification",
-                                verificationId);
-
-                        params.handleIntegrityVerificationFinished();
-                    }
-                    break;
-                }
-                case PACKAGE_VERIFIED: {
-                    final int verificationId = msg.arg1;
-
-                    final PackageVerificationState state = mPendingVerification.get(verificationId);
-                    if (state == null) {
-                        Slog.w(TAG, "Verification with id " + verificationId
-                                + " not found."
-                                + " It may be invalid or overridden by integrity verification");
-                        break;
-                    }
-
-                    final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;
-
-                    state.setVerifierResponse(response.callerUid, response.code);
-
-                    if (state.isVerificationComplete()) {
-                        final VerificationParams params = state.getVerificationParams();
-                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
-                        if (state.isInstallAllowed()) {
-                            broadcastPackageVerified(verificationId, originUri,
-                                    response.code, null, params.mDataLoaderType, params.getUser());
-                        } else {
-                            params.setReturnCode(
-                                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
-                                    "Install not allowed");
-                        }
-
-                        if (state.areAllVerificationsComplete()) {
-                            mPendingVerification.remove(verificationId);
-                        }
-
-                        Trace.asyncTraceEnd(
-                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
-                        params.handleVerificationFinished();
-                    }
-
-                    break;
-                }
-                case INTEGRITY_VERIFICATION_COMPLETE: {
-                    final int verificationId = msg.arg1;
-
-                    final PackageVerificationState state = mPendingVerification.get(verificationId);
-                    if (state == null) {
-                        Slog.w(TAG, "Integrity verification with id " + verificationId
-                                + " not found. It may be invalid or overridden by verifier");
-                        break;
-                    }
-
-                    final int response = (Integer) msg.obj;
-                    final VerificationParams params = state.getVerificationParams();
-                    final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
-                    state.setIntegrityVerificationResult(response);
-
-                    if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
-                        Slog.i(TAG, "Integrity check passed for " + originUri);
-                    } else {
-                        params.setReturnCode(
-                                PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
-                                "Integrity check failed for " + originUri);
-                    }
-
-                    if (state.areAllVerificationsComplete()) {
-                        mPendingVerification.remove(verificationId);
-                    }
-
-                    Trace.asyncTraceEnd(
-                            TRACE_TAG_PACKAGE_MANAGER,
-                            "integrity_verification",
-                            verificationId);
-
-                    params.handleIntegrityVerificationFinished();
-                    break;
-                }
-                case INSTANT_APP_RESOLUTION_PHASE_TWO: {
-                    InstantAppResolver.doInstantAppResolutionPhaseTwo(mContext,
-                            mInstantAppResolverConnection,
-                            (InstantAppRequest) msg.obj,
-                            mInstantAppInstallerActivity,
-                            mHandler);
-                    break;
-                }
-                case ENABLE_ROLLBACK_STATUS: {
-                    final int enableRollbackToken = msg.arg1;
-                    final int enableRollbackCode = msg.arg2;
-                    final VerificationParams params =
-                            mPendingEnableRollback.get(enableRollbackToken);
-                    if (params == null) {
-                        Slog.w(TAG, "Invalid rollback enabled token "
-                                + enableRollbackToken + " received");
-                        break;
-                    }
-
-                    mPendingEnableRollback.remove(enableRollbackToken);
-
-                    if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
-                        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);
-                    }
-
-                    Trace.asyncTraceEnd(
-                            TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
-
-                    params.handleRollbackEnabled();
-                    break;
-                }
-                case ENABLE_ROLLBACK_TIMEOUT: {
-                    final int enableRollbackToken = msg.arg1;
-                    final int sessionId = msg.arg2;
-                    final VerificationParams params =
-                            mPendingEnableRollback.get(enableRollbackToken);
-                    if (params != null) {
-                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
-                        Slog.w(TAG, "Enable rollback timed out for " + originUri);
-                        mPendingEnableRollback.remove(enableRollbackToken);
-
-                        Slog.w(TAG, "Continuing with installation of " + originUri);
-                        Trace.asyncTraceEnd(
-                                TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
-                        params.handleRollbackEnabled();
-                        Intent rollbackTimeoutIntent = new Intent(
-                                Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
-                        rollbackTimeoutIntent.putExtra(
-                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
-                                sessionId);
-                        rollbackTimeoutIntent.addFlags(
-                                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                        mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
-                                android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
-                    }
-                    break;
-                }
-                case DOMAIN_VERIFICATION: {
-                    int messageCode = msg.arg1;
-                    Object object = msg.obj;
-                    mDomainVerificationManager.runMessage(messageCode, object);
-                    break;
-                }
-                case SNAPSHOT_UNCORK: {
-                    int corking = sSnapshotCorked.decrementAndGet();
-                    if (TRACE_SNAPSHOTS && corking == 0) {
-                        Log.e(TAG, "snapshot: corking goes to zero in message handler");
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
-            boolean virtualPreload, boolean launchedForRestore, String installerPackage,
-            IPackageInstallObserver2 installObserver, int dataLoaderType) {
-        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.mPkg.getPath()));
-        if (succeeded && removedBeforeUpdate) {
-            Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
-                    + "could be executed");
-            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.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
-            if (args != null) {
-                synchronized (mInstallLock) {
-                    args.doPostDeleteLI(true);
-                }
-            }
-            notifyInstallObserver(res, installObserver);
-            return;
-        }
-
-        if (succeeded) {
-            // Clear the uid cache after we installed a new package.
-            mPerUidReadTimeoutsCache = null;
-
-            // Send the removed broadcasts
-            if (res.mRemovedInfo != null) {
-                res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
-            }
-
-            final String installerPackageName =
-                    res.mInstallerPackageName != null
-                            ? res.mInstallerPackageName
-                            : res.mRemovedInfo != null
-                                    ? res.mRemovedInfo.mInstallerPackageName
-                                    : null;
-
-            synchronized (mLock) {
-                mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
-            }
-
-            // Determine the set of users who are adding this package for
-            // the first time vs. those who are seeing an update.
-            int[] firstUserIds = EMPTY_INT_ARRAY;
-            int[] firstInstantUserIds = EMPTY_INT_ARRAY;
-            int[] updateUserIds = EMPTY_INT_ARRAY;
-            int[] instantUserIds = EMPTY_INT_ARRAY;
-            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);
-                    } else {
-                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
-                    }
-                    continue;
-                }
-                boolean isNew = true;
-                for (int origUser : res.mOrigUsers) {
-                    if (origUser == newUser) {
-                        isNew = false;
-                        break;
-                    }
-                }
-                if (isNew) {
-                    if (isInstantApp) {
-                        firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
-                    } else {
-                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
-                    }
-                } else {
-                    if (isInstantApp) {
-                        instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
-                    } else {
-                        updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
-                    }
-                }
-            }
-
-            // Send installed broadcasts if the package is not a static shared lib.
-            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.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.mUid);
-                if (update) {
-                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
-                }
-                extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
-                // Send to all running apps.
-                final SparseArray<int[]> newBroadcastAllowList;
-
-                synchronized (mLock) {
-                    newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
-                            getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
-                            updateUserIds, mSettings.getPackagesLocked());
-                }
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                        extras, 0 /*flags*/,
-                        null /*targetPackage*/, null /*finishedReceiver*/,
-                        updateUserIds, instantUserIds, newBroadcastAllowList, null);
-                if (installerPackageName != null) {
-                    // Send to the installer, even if it's not running.
-                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                            extras, 0 /*flags*/,
-                            installerPackageName, null /*finishedReceiver*/,
-                            updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
-                }
-                // if the required verifier is defined, but, is not the installer of record
-                // for the package, it gets notified
-                final boolean notifyVerifier = mRequiredVerifierPackage != null
-                        && !mRequiredVerifierPackage.equals(installerPackageName);
-                if (notifyVerifier) {
-                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                            extras, 0 /*flags*/,
-                            mRequiredVerifierPackage, null /*finishedReceiver*/,
-                            updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
-                }
-                // If package installer is defined, notify package installer about new
-                // app installed
-                if (mRequiredInstallerPackage != null) {
-                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                            extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
-                            mRequiredInstallerPackage, null /*finishedReceiver*/,
-                            firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
-                }
-
-                // Send replaced for users that don't see the package for the first time
-                if (update) {
-                    sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
-                            packageName, extras, 0 /*flags*/,
-                            null /*targetPackage*/, null /*finishedReceiver*/,
-                            updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
-                            null);
-                    if (installerPackageName != null) {
-                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
-                                extras, 0 /*flags*/,
-                                installerPackageName, null /*finishedReceiver*/,
-                                updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
-                    }
-                    if (notifyVerifier) {
-                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
-                                extras, 0 /*flags*/,
-                                mRequiredVerifierPackage, null /*finishedReceiver*/,
-                                updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
-                    }
-                    sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
-                            null /*package*/, null /*extras*/, 0 /*flags*/,
-                            packageName /*targetPackage*/,
-                            null /*finishedReceiver*/, updateUserIds, instantUserIds,
-                            null /*broadcastAllowList*/,
-                            getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
-                                    .toBundle());
-                } 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) {
-                        Slog.i(TAG, "Post-restore of " + packageName
-                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
-                    }
-                    sendFirstLaunchBroadcast(packageName, installerPackage,
-                            firstUserIds, firstInstantUserIds);
-                }
-
-                // Send broadcast package appeared if external for all users
-                if (res.mPkg.isExternalStorage()) {
-                    if (!update) {
-                        final StorageManager storage = mInjector.getSystemService(
-                                StorageManager.class);
-                        VolumeInfo volume =
-                                storage.findVolumeByUuid(
-                                        res.mPkg.getStorageUuid().toString());
-                        int packageExternalStorageType =
-                                getPackageExternalStorageType(volume, res.mPkg.isExternalStorage());
-                        // If the package was installed externally, log it.
-                        if (packageExternalStorageType != StorageEnums.UNKNOWN) {
-                            FrameworkStatsLog.write(
-                                    FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
-                                    packageExternalStorageType, packageName);
-                        }
-                    }
-                    if (DEBUG_INSTALL) {
-                        Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
-                    }
-                    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.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())),
-                            pkg.getUid(), null);
-                }
-            }
-
-            // Work that needs to happen on first install within each user
-            if (firstUserIds != null && firstUserIds.length > 0) {
-                for (int userId : firstUserIds) {
-                    restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
-                            userId);
-                }
-            }
-
-            if (allNewUsers && !update) {
-                notifyPackageAdded(packageName, res.mUid);
-            } else {
-                notifyPackageChanged(packageName, res.mUid);
-            }
-
-            // Log current value of "unknown sources" setting
-            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
-                    getUnknownSourcesSettings());
-
-            // Remove the replaced package's older resources safely now
-            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
-                    // they may still be in use by the running application. This mitigates problems
-                    // in cases where resources or code is loaded by a new Activity before
-                    // ApplicationInfo changes have propagated to all application threads.
-                    scheduleDeferredNoKillPostDelete(args);
-                } else {
-                    synchronized (mInstallLock) {
-                        args.doPostDeleteLI(true);
-                    }
-                }
-            } else {
-                // Force a gc to clear up things. Ask for a background one, it's fine to go on
-                // and not block here.
-                VMRuntime.getRuntime().requestConcurrentGC();
-            }
 
-            // Notify DexManager that the package was installed for new users.
-            // The updated users should already be indexed and the package code paths
-            // should not change.
-            // Don't notify the manager for ephemeral apps as they are not expected to
-            // survive long enough to benefit of background optimizations.
-            for (int userId : firstUserIds) {
-                PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
-                // There's a race currently where some install events may interleave with an
-                // uninstall. This can lead to package info being null (b/36642664).
-                if (info != null) {
-                    mDexManager.notifyPackageInstalled(info, userId);
-                }
-            }
-        }
 
-        final boolean deferInstallObserver = succeeded && update && !killApp;
-        if (deferInstallObserver) {
-            scheduleDeferredNoKillInstallObserver(res, installObserver);
-        } else {
-            notifyInstallObserver(res, installObserver);
-        }
-    }
 
     @Override
     public void notifyPackagesReplacedReceived(String[] packages) {
@@ -6391,12 +6136,12 @@
         }
     }
 
-    private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
+    void scheduleDeferredNoKillPostDelete(InstallArgs args) {
         Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
         mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
     }
 
-    private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
+    void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
             IPackageInstallObserver2 observer) {
         String packageName = info.mPkg.getPackageName();
         mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
@@ -6484,7 +6229,7 @@
      * corresponding {@link StorageEnums} storage type value if it is.
      * corresponding {@link StorageEnums} storage type value if it is.
      */
-    private static int getPackageExternalStorageType(VolumeInfo packageVolume,
+    static int getPackageExternalStorageType(VolumeInfo packageVolume,
             boolean packageIsExternal) {
         if (packageVolume != null) {
             DiskInfo disk = packageVolume.getDisk();
@@ -6679,7 +6424,7 @@
                     HandlerThread thread = new ServiceThread(TAG,
                             Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
                     thread.start();
-                    return pm.new PackageHandler(thread.getLooper());
+                    return new PackageHandler(thread.getLooper(), pm);
                 },
                 new DefaultSystemWrapper(),
                 LocalServices::getService,
@@ -6785,53 +6530,6 @@
         }
     }
 
-    @VisibleForTesting
-    public static class ScanPartition extends SystemPartition {
-        @ScanFlags
-        public final int scanFlag;
-
-        public ScanPartition(@NonNull SystemPartition partition) {
-            super(partition);
-            scanFlag = scanFlagForPartition(partition);
-        }
-
-        /**
-         * Creates a partition containing the same folders as the original partition but with a
-         * different root folder. The new partition will include the scan flags of the original
-         * partition along with any specified additional scan flags.
-         */
-        public ScanPartition(@NonNull File folder, @NonNull ScanPartition original,
-                @ScanFlags int additionalScanFlag) {
-            super(folder, original);
-            this.scanFlag = original.scanFlag | additionalScanFlag;
-        }
-
-        private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
-            switch (partition.type) {
-                case PackagePartitions.PARTITION_SYSTEM:
-                    return 0;
-                case PackagePartitions.PARTITION_VENDOR:
-                    return SCAN_AS_VENDOR;
-                case PackagePartitions.PARTITION_ODM:
-                    return SCAN_AS_ODM;
-                case PackagePartitions.PARTITION_OEM:
-                    return SCAN_AS_OEM;
-                case PackagePartitions.PARTITION_PRODUCT:
-                    return SCAN_AS_PRODUCT;
-                case PackagePartitions.PARTITION_SYSTEM_EXT:
-                    return SCAN_AS_SYSTEM_EXT;
-                default:
-                    throw new IllegalStateException("Unable to determine scan flag for "
-                            + partition.getFolder());
-            }
-        }
-
-        @Override
-        public String toString() {
-            return getFolder().getAbsolutePath() + ":" + scanFlag;
-        }
-    }
-
     // Link watchables to the class
     private void registerObserver() {
         mPackages.registerObserver(mWatcher);
@@ -7142,6 +6840,7 @@
             t.traceEnd();
 
             mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
+            mPermissionManager.readLegacyPermissionStateTEMP();
 
             if (!mOnlyCore && mFirstBoot) {
                 requestCopyPreoptedFiles();
@@ -7170,7 +6869,6 @@
                 Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
             }
 
-            File frameworkDir = new File(Environment.getRootDirectory(), "framework");
 
             final VersionInfo ver = mSettings.getInternalVersion();
             mIsUpgrade =
@@ -7222,286 +6920,23 @@
             // Prepare apex package info before scanning APKs, these information are needed when
             // scanning apk in apex.
             mApexManager.scanApexPackagesTraced(packageParser, executorService);
-            // Collect vendor/product/system_ext overlay packages. (Do this before scanning
-            // any apps.)
-            // For security and version matching reason, only consider overlay packages if they
-            // reside in the right directory.
-            for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
-                final ScanPartition partition = mDirsToScanAsSystem.get(i);
-                if (partition.getOverlayFolder() == null) {
-                    continue;
-                }
-                scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
-                        systemScanFlags | partition.scanFlag, 0,
-                        packageParser, executorService);
-            }
 
-            scanDirTracedLI(frameworkDir, systemParseFlags,
-                    systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
-                    packageParser, executorService);
-            if (!mPackages.containsKey("android")) {
-                throw new IllegalStateException(
-                        "Failed to load frameworks package; check log for warnings");
-            }
-            for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
-                final ScanPartition partition = mDirsToScanAsSystem.get(i);
-                if (partition.getPrivAppFolder() != null) {
-                    scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
-                            systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
-                            packageParser, executorService);
-                }
-                scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
-                        systemScanFlags | partition.scanFlag, 0,
-                        packageParser, executorService);
-            }
-
+            final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+            helper.scanSystemDirs(mDirsToScanAsSystem, mIsUpgrade,
+                    packageParser, executorService, mPlatformPackage, mIsPreNMR1Upgrade,
+                    systemParseFlags, systemScanFlags);
             // Parse overlay configuration files to set default enable state, mutability, and
             // priority of system overlays.
             mOverlayConfig = OverlayConfig.initializeSystemInstance(
                     consumer -> mPmInternal.forEachPackage(
                             pkg -> consumer.accept(pkg, pkg.isSystem())));
-
-            // Prune any system packages that no longer exist.
-            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
-            // Stub packages must either be replaced with full versions in the /data
-            // partition or be disabled.
-            final List<String> stubSystemApps = new ArrayList<>();
             final int[] userIds = mUserManager.getUserIds();
-            if (!mOnlyCore) {
-                // do this first before mucking with mPackages for the "expecting better" case
-                final int numPackages = mPackages.size();
-                for (int index = 0; index < numPackages; index++) {
-                    final AndroidPackage pkg = mPackages.valueAt(index);
-                    if (pkg.isStub()) {
-                        stubSystemApps.add(pkg.getPackageName());
-                    }
-                }
-
-                // Iterates PackageSettings in reversed order because the item could be removed
-                // during the iteration.
-                for (int index = packageSettings.size() - 1; index >= 0; index--) {
-                    final PackageSetting ps = packageSettings.valueAt(index);
-
-                    /*
-                     * If this is not a system app, it can't be a
-                     * disable system app.
-                     */
-                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-                        continue;
-                    }
-
-                    /*
-                     * If the package is scanned, it's not erased.
-                     */
-                    final AndroidPackage scannedPkg = mPackages.get(ps.name);
-                    if (scannedPkg != null) {
-                        /*
-                         * If the system app is both scanned and in the
-                         * disabled packages list, then it must have been
-                         * added via OTA. Remove it from the currently
-                         * scanned package so the previously user-installed
-                         * application can be scanned.
-                         */
-                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
-                            logCriticalInfo(Log.WARN,
-                                    "Expecting better updated system app for " + ps.name
-                                    + "; removing system app.  Last known"
-                                    + " codePath=" + ps.getPathString()
-                                    + ", versionCode=" + ps.versionCode
-                                    + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
-                            removePackageLI(scannedPkg, true);
-                            mExpectingBetter.put(ps.name, ps.getPath());
-                        }
-
-                        continue;
-                    }
-
-                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
-                        logCriticalInfo(Log.WARN, "System package " + ps.name
-                                + " no longer exists; it's data will be wiped");
-                        removePackageDataLIF(ps, userIds, null, 0, false);
-                    } else {
-                        // we still have a disabled system package, but, it still might have
-                        // been removed. check the code path still exists and check there's
-                        // still a package. the latter can happen if an OTA keeps the same
-                        // code path, but, changes the package name.
-                        final PackageSetting disabledPs =
-                                mSettings.getDisabledSystemPkgLPr(ps.name);
-                        if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
-                                || disabledPs.pkg == null) {
-                            possiblyDeletedUpdatedSystemApps.add(ps.name);
-                        } else {
-                            // We're expecting that the system app should remain disabled, but add
-                            // it to expecting better to recover in case the data version cannot
-                            // be scanned.
-                            mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
-                        }
-                    }
-                }
-            }
-
-            final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
-
-            // Remove any shared userIDs that have no associated packages
-            mSettings.pruneSharedUsersLPw();
-            final long systemScanTime = SystemClock.uptimeMillis() - startTime;
-            final int systemPackagesCount = mPackages.size();
-            Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
-                    + " ms, packageCount: " + systemPackagesCount
-                    + " , timePerPackage: "
-                    + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
-                    + " , cached: " + cachedSystemApps);
-            if (mIsUpgrade && systemPackagesCount > 0) {
-                //CHECKSTYLE:OFF IndentationCheck
-                FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
-                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
-                    systemScanTime / systemPackagesCount);
-                //CHECKSTYLE:ON IndentationCheck
-            }
-            if (!mOnlyCore) {
-                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
-                        SystemClock.uptimeMillis());
-                scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
-                        packageParser, executorService);
-
-            }
-
+            helper.cleanupSystemPackagesAndInstallStubs(mDirsToScanAsSystem,
+                    mIsUpgrade, packageParser, executorService, mOnlyCore, packageSettings,
+                    startTime, mAppInstallDir, mPlatformPackage, mIsPreNMR1Upgrade,
+                    scanFlags, systemParseFlags, systemScanFlags, userIds);
             packageParser.close();
 
-            List<Runnable> unfinishedTasks = executorService.shutdownNow();
-            if (!unfinishedTasks.isEmpty()) {
-                throw new IllegalStateException("Not all tasks finished before calling close: "
-                        + unfinishedTasks);
-            }
-
-            if (!mOnlyCore) {
-                // Remove disable package settings for updated system apps that were
-                // removed via an OTA. If the update is no longer present, remove the
-                // app completely. Otherwise, revoke their system privileges.
-                for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
-                    final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
-                    final AndroidPackage pkg = mPackages.get(packageName);
-                    final String msg;
-
-                    // remove from the disabled system list; do this first so any future
-                    // scans of this package are performed without this state
-                    mSettings.removeDisabledSystemPackageLPw(packageName);
-
-                    if (pkg == null) {
-                        // should have found an update, but, we didn't; remove everything
-                        msg = "Updated system package " + packageName
-                                + " no longer exists; removing its data";
-                        // Actual deletion of code and data will be handled by later
-                        // reconciliation step
-                    } else {
-                        // found an update; revoke system privileges
-                        msg = "Updated system package " + packageName
-                                + " no longer exists; rescanning package on data";
-
-                        // NOTE: We don't do anything special if a stub is removed from the
-                        // system image. But, if we were [like removing the uncompressed
-                        // version from the /data partition], this is where it'd be done.
-
-                        // remove the package from the system and re-scan it without any
-                        // special privileges
-                        removePackageLI(pkg, true);
-                        try {
-                            final File codePath = new File(pkg.getPath());
-                            scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
-                        } catch (PackageManagerException e) {
-                            Slog.e(TAG, "Failed to parse updated, ex-system package: "
-                                    + e.getMessage());
-                        }
-                    }
-
-                    // one final check. if we still have a package setting [ie. it was
-                    // previously scanned and known to the system], but, we don't have
-                    // a package [ie. there was an error scanning it from the /data
-                    // partition], completely remove the package data.
-                    final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                    if (ps != null && mPackages.get(packageName) == null) {
-                        removePackageDataLIF(ps, userIds, null, 0, false);
-
-                    }
-                    logCriticalInfo(Log.WARN, msg);
-                }
-
-                /*
-                 * Make sure all system apps that we expected to appear on
-                 * the userdata partition actually showed up. If they never
-                 * appeared, crawl back and revive the system version.
-                 */
-                for (int i = 0; i < mExpectingBetter.size(); i++) {
-                    final String packageName = mExpectingBetter.keyAt(i);
-                    if (!mPackages.containsKey(packageName)) {
-                        final File scanFile = mExpectingBetter.valueAt(i);
-
-                        logCriticalInfo(Log.WARN, "Expected better " + packageName
-                                + " but never showed up; reverting to system");
-
-                        @ParseFlags int reparseFlags = 0;
-                        @ScanFlags int rescanFlags = 0;
-                        for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
-                            final ScanPartition partition = mDirsToScanAsSystem.get(i1);
-                            if (partition.containsPrivApp(scanFile)) {
-                                reparseFlags = systemParseFlags;
-                                rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
-                                        | partition.scanFlag;
-                                break;
-                            }
-                            if (partition.containsApp(scanFile)) {
-                                reparseFlags = systemParseFlags;
-                                rescanFlags = systemScanFlags | partition.scanFlag;
-                                break;
-                            }
-                        }
-                        if (rescanFlags == 0) {
-                            Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
-                            continue;
-                        }
-                        mSettings.enableSystemPackageLPw(packageName);
-
-                        try {
-                            final AndroidPackage newPkg = scanPackageTracedLI(
-                                    scanFile, reparseFlags, rescanFlags, 0, null);
-                            // We rescanned a stub, add it to the list of stubbed system packages
-                            if (newPkg.isStub()) {
-                                stubSystemApps.add(packageName);
-                            }
-                        } catch (PackageManagerException e) {
-                            Slog.e(TAG, "Failed to parse original system package: "
-                                    + e.getMessage());
-                        }
-                    }
-                }
-
-                // Uncompress and install any stubbed system applications.
-                // This must be done last to ensure all stubs are replaced or disabled.
-                installSystemStubPackages(stubSystemApps, scanFlags);
-
-                final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
-                                - cachedSystemApps;
-
-                final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
-                final int dataPackagesCount = mPackages.size() - systemPackagesCount;
-                Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
-                        + " ms, packageCount: " + dataPackagesCount
-                        + " , timePerPackage: "
-                        + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
-                        + " , cached: " + cachedNonSystemApps);
-                if (mIsUpgrade && dataPackagesCount > 0) {
-                    //CHECKSTYLE:OFF IndentationCheck
-                    FrameworkStatsLog.write(
-                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
-                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
-                        dataScanTime / dataPackagesCount);
-                    //CHECKSTYLE:OFF IndentationCheck
-                }
-            }
-            mExpectingBetter.clear();
-
-            mSettings.pruneRenamedPackagesLPw();
-
             // Resolve the storage manager.
             mStorageManagerPackage = getStorageManagerPackageName();
 
@@ -7558,7 +6993,6 @@
                     + ((SystemClock.uptimeMillis()-startTime)/1000f)
                     + " seconds");
 
-            mPermissionManager.readLegacyPermissionStateTEMP();
             // If the build fingerprint has changed since the last time we booted,
             // we need to re-grant app permission to catch any new ones that
             // appear.  This is really a hack, and means that apps can in some
@@ -7593,7 +7027,7 @@
             }
             List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
                     UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
-                    true /* onlyCoreApps */);
+                    true /* onlyCoreApps */, null);
             mPrepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
                 TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
                         Trace.TRACE_TAG_PACKAGE_MANAGER);
@@ -7796,234 +7230,10 @@
         Slog.i(TAG, "Fix for b/169414761 is applied");
     }
 
-    /**
-     * Uncompress and install stub applications.
-     * <p>In order to save space on the system partition, some applications are shipped in a
-     * compressed form. In addition the compressed bits for the full application, the
-     * system image contains a tiny stub comprised of only the Android manifest.
-     * <p>During the first boot, attempt to uncompress and install the full application. If
-     * the application can't be installed for any reason, disable the stub and prevent
-     * uncompressing the full application during future boots.
-     * <p>In order to forcefully attempt an installation of a full application, go to app
-     * settings and enable the application.
-     */
-    private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
-            @ScanFlags int scanFlags) {
-        for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
-            final String packageName = systemStubPackageNames.get(i);
-            // skip if the system package is already disabled
-            if (mSettings.isDisabledSystemPackageLPr(packageName)) {
-                systemStubPackageNames.remove(i);
-                continue;
-            }
-            // skip if the package isn't installed (?!); this should never happen
-            final AndroidPackage pkg = mPackages.get(packageName);
-            if (pkg == null) {
-                systemStubPackageNames.remove(i);
-                continue;
-            }
-            // skip if the package has been disabled by the user
-            final PackageSetting ps = mSettings.getPackageLPr(packageName);
-            if (ps != null) {
-                final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
-                if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
-                    systemStubPackageNames.remove(i);
-                    continue;
-                }
-            }
 
-            // install the package to replace the stub on /system
-            try {
-                installStubPackageLI(pkg, 0, scanFlags);
-                ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
-                        UserHandle.USER_SYSTEM, "android");
-                systemStubPackageNames.remove(i);
-            } catch (PackageManagerException e) {
-                Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
-            }
 
-            // any failed attempt to install the package will be cleaned up later
-        }
 
-        // disable any stub still left; these failed to install the full application
-        for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
-            final String pkgName = systemStubPackageNames.get(i);
-            final PackageSetting ps = mSettings.getPackageLPr(pkgName);
-            ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                    UserHandle.USER_SYSTEM, "android");
-            logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
-        }
-    }
 
-    /**
-     * Extract, install and enable a stub package.
-     * <p>If the compressed file can not be extracted / installed for any reason, the stub
-     * APK will be installed and the package will be disabled. To recover from this situation,
-     * the user will need to go into system settings and re-enable the package.
-     */
-    private boolean enableCompressedPackage(AndroidPackage stubPkg,
-            @NonNull PackageSetting stubPkgSetting) {
-        final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
-                | ParsingPackageUtils.PARSE_ENFORCE_CODE;
-        synchronized (mInstallLock) {
-            final AndroidPackage pkg;
-            try (PackageFreezer freezer =
-                    freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
-                pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
-                synchronized (mLock) {
-                    prepareAppDataAfterInstallLIF(pkg);
-                    try {
-                        updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
-                                Collections.unmodifiableMap(mPackages));
-                    } catch (PackageManagerException e) {
-                        Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
-                    }
-                    mPermissionManager.onPackageInstalled(pkg,
-                            PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
-                            UserHandle.USER_ALL);
-                    writeSettingsLPrTEMP();
-                }
-            } catch (PackageManagerException e) {
-                // Whoops! Something went very wrong; roll back to the stub and disable the package
-                try (PackageFreezer freezer =
-                        freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
-                    synchronized (mLock) {
-                        // NOTE: Ensure the system package is enabled; even for a compressed stub.
-                        // If we don't, installing the system package fails during scan
-                        enableSystemPackageLPw(stubPkg);
-                    }
-                    installPackageFromSystemLIF(stubPkg.getPath(),
-                            mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/,
-                            true /*writeSettings*/);
-                } catch (PackageManagerException pme) {
-                    // Serious WTF; we have to be able to install the stub
-                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
-                            pme);
-                } finally {
-                    // Disable the package; the stub by itself is not runnable
-                    synchronized (mLock) {
-                        final PackageSetting stubPs = mSettings.getPackageLPr(
-                                stubPkg.getPackageName());
-                        if (stubPs != null) {
-                            stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
-                                    UserHandle.USER_SYSTEM, "android");
-                        }
-                        writeSettingsLPrTEMP();
-                    }
-                }
-                return false;
-            }
-            clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
-                    | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-            mDexManager.notifyPackageUpdated(pkg.getPackageName(),
-                    pkg.getBaseApkPath(), pkg.getSplitCodePaths());
-        }
-        return true;
-    }
-
-    private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
-            @ParseFlags int parseFlags, @ScanFlags int scanFlags)
-                    throws PackageManagerException {
-        if (DEBUG_COMPRESSION) {
-            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
-        }
-        // uncompress the binary to its eventual destination on /data
-        final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
-        if (scanFile == null) {
-            throw new PackageManagerException(
-                    "Unable to decompress stub at " + stubPkg.getPath());
-        }
-        synchronized (mLock) {
-            mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
-        }
-        removePackageLI(stubPkg, true /*chatty*/);
-        try {
-            return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
-        } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
-                    e);
-            // Remove the failed install
-            removeCodePathLI(scanFile);
-            throw e;
-        }
-    }
-
-    /**
-     * Decompresses the given package on the system image onto
-     * the /data partition.
-     * @return The directory the package was decompressed into. Otherwise, {@code null}.
-     */
-    private File decompressPackage(String packageName, String codePath) {
-        final File[] compressedFiles = getCompressedFiles(codePath);
-        if (compressedFiles == null || compressedFiles.length == 0) {
-            if (DEBUG_COMPRESSION) {
-                Slog.i(TAG, "No files to decompress: " + codePath);
-            }
-            return null;
-        }
-        final File dstCodePath =
-                getNextCodePath(Environment.getDataAppDirectory(null), packageName);
-        int ret = PackageManager.INSTALL_SUCCEEDED;
-        try {
-            makeDirRecursive(dstCodePath, 0755);
-            for (File srcFile : compressedFiles) {
-                final String srcFileName = srcFile.getName();
-                final String dstFileName = srcFileName.substring(
-                        0, srcFileName.length() - COMPRESSED_EXTENSION.length());
-                final File dstFile = new File(dstCodePath, dstFileName);
-                ret = decompressFile(srcFile, dstFile);
-                if (ret != PackageManager.INSTALL_SUCCEEDED) {
-                    logCriticalInfo(Log.ERROR, "Failed to decompress"
-                            + "; pkg: " + packageName
-                            + ", file: " + dstFileName);
-                    break;
-                }
-            }
-        } catch (ErrnoException e) {
-            logCriticalInfo(Log.ERROR, "Failed to decompress"
-                    + "; pkg: " + packageName
-                    + ", err: " + e.errno);
-        }
-        if (ret == PackageManager.INSTALL_SUCCEEDED) {
-            final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
-            NativeLibraryHelper.Handle handle = null;
-            try {
-                handle = NativeLibraryHelper.Handle.create(dstCodePath);
-                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
-                        null /*abiOverride*/, false /*isIncremental*/);
-            } catch (IOException e) {
-                logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
-                        + "; pkg: " + packageName);
-                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-            } finally {
-                IoUtils.closeQuietly(handle);
-            }
-        }
-        if (ret == PackageManager.INSTALL_SUCCEEDED) {
-            // NOTE: During boot, we have to delay releasing cblocks for no other reason than
-            // we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}.
-            // When we no longer need to read that setting, cblock release can occur always
-            // occur here directly
-            if (!mSystemReady) {
-                if (mReleaseOnSystemReady == null) {
-                    mReleaseOnSystemReady = new ArrayList<>();
-                }
-                mReleaseOnSystemReady.add(dstCodePath);
-            } else {
-                final ContentResolver resolver = mContext.getContentResolver();
-                F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
-            }
-        }
-        if (ret != PackageManager.INSTALL_SUCCEEDED) {
-            if (!dstCodePath.exists()) {
-                return null;
-            }
-            removeCodePathLI(dstCodePath);
-            return null;
-        }
-
-        return dstCodePath;
-    }
 
     @GuardedBy("mLock")
     void updateInstantAppInstallerLocked(String modifiedPackage) {
@@ -8136,7 +7346,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) {
@@ -8232,7 +7442,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++) {
@@ -8260,7 +7470,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++) {
@@ -8973,7 +8183,7 @@
     /**
      * Update given intent when being used to request {@link ResolveInfo}.
      */
-    private Intent updateIntentForResolve(Intent intent) {
+    private static Intent updateIntentForResolve(Intent intent) {
         if (intent.getSelector() != null) {
             intent = intent.getSelector();
         }
@@ -9778,7 +8988,7 @@
         return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
-    private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
+    static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
         return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
     }
 
@@ -9786,7 +8996,7 @@
         return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
-    private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
+    static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
         return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
     }
 
@@ -10326,69 +9536,38 @@
     }
 
     @GuardedBy("mLock")
-    private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
+    private ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+            String resolvedType,
             int flags, List<ResolveInfo> query, boolean debug, int userId) {
-        final int N = query.size();
-        PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
-        // Get the list of persistent preferred activities that handle the intent
-        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
-        List<PersistentPreferredActivity> pprefs = ppir != null
-                ? ppir.queryIntent(intent, resolvedType,
-                        (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
-                        userId)
-                : null;
-        if (pprefs != null && pprefs.size() > 0) {
-            final int M = pprefs.size();
-            for (int i=0; i<M; i++) {
-                final PersistentPreferredActivity ppa = pprefs.get(i);
-                if (DEBUG_PREFERRED || debug) {
-                    Slog.v(TAG, "Checking PersistentPreferredActivity ds="
-                            + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
-                            + "\n  component=" + ppa.mComponent);
-                    ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                }
-                final ActivityInfo ai = getActivityInfo(ppa.mComponent,
-                        flags | MATCH_DISABLED_COMPONENTS, userId);
-                if (DEBUG_PREFERRED || debug) {
-                    Slog.v(TAG, "Found persistent preferred activity:");
-                    if (ai != null) {
-                        ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                    } else {
-                        Slog.v(TAG, "  null");
-                    }
-                }
-                if (ai == null) {
-                    // This previously registered persistent preferred activity
-                    // component is no longer known. Ignore it and do NOT remove it.
-                    continue;
-                }
-                for (int j=0; j<N; j++) {
-                    final ResolveInfo ri = query.get(j);
-                    if (!ri.activityInfo.applicationInfo.packageName
-                            .equals(ai.applicationInfo.packageName)) {
-                        continue;
-                    }
-                    if (!ri.activityInfo.name.equals(ai.name)) {
-                        continue;
-                    }
-                    //  Found a persistent preference that can handle the intent.
-                    if (DEBUG_PREFERRED || debug) {
-                        Slog.v(TAG, "Returning persistent preferred activity: " +
-                                ri.activityInfo.packageName + "/" + ri.activityInfo.name);
-                    }
-                    return ri;
-                }
-            }
-        }
-        return null;
+        return mComputer.findPersistentPreferredActivityLP(intent,
+                resolvedType,
+                flags, query, debug, userId);
     }
 
-    private boolean isHomeIntent(Intent intent) {
+    private static boolean isHomeIntent(Intent intent) {
         return ACTION_MAIN.equals(intent.getAction())
                 && intent.hasCategory(CATEGORY_HOME)
                 && intent.hasCategory(CATEGORY_DEFAULT);
     }
 
+
+    // findPreferredActivityBody returns two items: a "things changed" flag and a
+    // ResolveInfo, which is the preferred activity itself.
+    private static class FindPreferredActivityBodyResult {
+        boolean mChanged;
+        ResolveInfo mPreferredResolveInfo;
+    }
+
+    private FindPreferredActivityBodyResult findPreferredActivityInternal(
+            Intent intent, String resolvedType, int flags,
+            List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+        return mComputer.findPreferredActivityInternal(
+            intent, resolvedType, flags,
+            query, always,
+            removeMatches, debug, userId, queryMayBeFiltered);
+    }
+
     ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
             List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId) {
@@ -10407,206 +9586,22 @@
                     + " is holding mLock", new Throwable());
         }
         if (!mUserManager.exists(userId)) return null;
-        final int callingUid = Binder.getCallingUid();
-        // Do NOT hold the packages lock; this calls up into the settings provider which
-        // could cause a deadlock.
-        final boolean isDeviceProvisioned =
-                android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                        android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
-        flags = updateFlagsForResolve(
-                flags, userId, callingUid, false /*includeInstantApps*/,
-                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
-                        flags));
-        intent = updateIntentForResolve(intent);
-        // writer
-        synchronized (mLock) {
-            // Try to find a matching persistent preferred activity.
-            ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
-                    debug, userId);
 
-            // If a persistent preferred activity matched, use it.
-            if (pri != null) {
-                return pri;
+        FindPreferredActivityBodyResult body = findPreferredActivityInternal(
+                intent, resolvedType, flags, query, always,
+                removeMatches, debug, userId, queryMayBeFiltered);
+        if (body.mChanged) {
+            if (DEBUG_PREFERRED) {
+                Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
             }
-
-            PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
-            // Get the list of preferred activities that handle the intent
-            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
-            List<PreferredActivity> prefs = pir != null
-                    ? pir.queryIntent(intent, resolvedType,
-                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
-                            userId)
-                    : null;
-            if (prefs != null && prefs.size() > 0) {
-                boolean changed = false;
-                try {
-                    // First figure out how good the original match set is.
-                    // We will only allow preferred activities that came
-                    // from the same match quality.
-                    int match = 0;
-
-                    if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
-
-                    final int N = query.size();
-                    for (int j=0; j<N; j++) {
-                        final ResolveInfo ri = query.get(j);
-                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo
-                                + ": 0x" + Integer.toHexString(match));
-                        if (ri.match > match) {
-                            match = ri.match;
-                        }
-                    }
-
-                    if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x"
-                            + Integer.toHexString(match));
-
-                    match &= IntentFilter.MATCH_CATEGORY_MASK;
-                    final int M = prefs.size();
-                    for (int i=0; i<M; i++) {
-                        final PreferredActivity pa = prefs.get(i);
-                        if (DEBUG_PREFERRED || debug) {
-                            Slog.v(TAG, "Checking PreferredActivity ds="
-                                    + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
-                                    + "\n  component=" + pa.mPref.mComponent);
-                            pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                        }
-                        if (pa.mPref.mMatch != match) {
-                            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match "
-                                    + Integer.toHexString(pa.mPref.mMatch));
-                            continue;
-                        }
-                        // If it's not an "always" type preferred activity and that's what we're
-                        // looking for, skip it.
-                        if (always && !pa.mPref.mAlways) {
-                            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
-                            continue;
-                        }
-                        final ActivityInfo ai = getActivityInfo(
-                                pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
-                                        | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                                userId);
-                        if (DEBUG_PREFERRED || debug) {
-                            Slog.v(TAG, "Found preferred activity:");
-                            if (ai != null) {
-                                ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                            } else {
-                                Slog.v(TAG, "  null");
-                            }
-                        }
-                        final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
-                                && !isDeviceProvisioned;
-                        final boolean allowSetMutation = !excludeSetupWizardHomeActivity
-                                && !queryMayBeFiltered;
-                        if (ai == null) {
-                            // Do not remove launcher's preferred activity during SetupWizard
-                            // due to it may not install yet
-                            if (!allowSetMutation) {
-                                continue;
-                            }
-
-                            // This previously registered preferred activity
-                            // component is no longer known.  Most likely an update
-                            // to the app was installed and in the new version this
-                            // component no longer exists.  Clean it up by removing
-                            // it from the preferred activities list, and skip it.
-                            Slog.w(TAG, "Removing dangling preferred activity: "
-                                    + pa.mPref.mComponent);
-                            pir.removeFilter(pa);
-                            changed = true;
-                            continue;
-                        }
-                        for (int j=0; j<N; j++) {
-                            final ResolveInfo ri = query.get(j);
-                            if (!ri.activityInfo.applicationInfo.packageName
-                                    .equals(ai.applicationInfo.packageName)) {
-                                continue;
-                            }
-                            if (!ri.activityInfo.name.equals(ai.name)) {
-                                continue;
-                            }
-
-                            if (removeMatches && allowSetMutation) {
-                                pir.removeFilter(pa);
-                                changed = true;
-                                if (DEBUG_PREFERRED) {
-                                    Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
-                                }
-                                break;
-                            }
-
-                            // Okay we found a previously set preferred or last chosen app.
-                            // If the result set is different from when this
-                            // was created, and is not a subset of the preferred set, we need to
-                            // clear it and re-ask the user their preference, if we're looking for
-                            // an "always" type entry.
-
-                            if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
-                                if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
-                                    if (allowSetMutation) {
-                                        // some components of the set are no longer present in
-                                        // the query, but the preferred activity can still be reused
-                                        if (DEBUG_PREFERRED) {
-                                            Slog.i(TAG, "Result set changed, but PreferredActivity"
-                                                    + " is still valid as only non-preferred"
-                                                    + " components were removed for " + intent
-                                                    + " type " + resolvedType);
-                                        }
-                                        // remove obsolete components and re-add the up-to-date
-                                        // filter
-                                        PreferredActivity freshPa = new PreferredActivity(pa,
-                                                pa.mPref.mMatch,
-                                                pa.mPref.discardObsoleteComponents(query),
-                                                pa.mPref.mComponent,
-                                                pa.mPref.mAlways);
-                                        pir.removeFilter(pa);
-                                        pir.addFilter(freshPa);
-                                        changed = true;
-                                    } else {
-                                        if (DEBUG_PREFERRED) {
-                                            Slog.i(TAG, "Do not remove preferred activity");
-                                        }
-                                    }
-                                } else {
-                                    if (allowSetMutation) {
-                                        Slog.i(TAG,
-                                                "Result set changed, dropping preferred activity "
-                                                        + "for " + intent + " type "
-                                                        + resolvedType);
-                                        if (DEBUG_PREFERRED) {
-                                            Slog.v(TAG,
-                                                    "Removing preferred activity since set changed "
-                                                            + pa.mPref.mComponent);
-                                        }
-                                        pir.removeFilter(pa);
-                                        // Re-add the filter as a "last chosen" entry (!always)
-                                        PreferredActivity lastChosen = new PreferredActivity(
-                                                pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
-                                                false);
-                                        pir.addFilter(lastChosen);
-                                        changed = true;
-                                    }
-                                    return null;
-                                }
-                            }
-
-                            // Yay! Either the set matched or we're looking for the last chosen
-                            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: "
-                                    + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
-                            return ri;
-                        }
-                    }
-                } finally {
-                    if (changed) {
-                        if (DEBUG_PREFERRED) {
-                            Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
-                        }
-                        scheduleWritePackageRestrictionsLocked(userId);
-                    }
-                }
+            synchronized (mLock) {
+                scheduleWritePackageRestrictionsLocked(userId);
             }
         }
-        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return");
-        return null;
+        if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) {
+            Slog.v(TAG, "No preferred activity to return");
+        }
+        return body.mPreferredResolveInfo;
     }
 
     /*
@@ -10939,30 +9934,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
@@ -10998,40 +9995,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
@@ -11073,6 +10074,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) {
@@ -11683,169 +10746,20 @@
         return finalList;
     }
 
-    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
-            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
-        try {
-            scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-    }
-
-    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
-            PackageParser2 packageParser, ExecutorService executorService) {
-        final File[] files = scanDir.listFiles();
-        if (ArrayUtils.isEmpty(files)) {
-            Log.d(TAG, "No files in app dir " + scanDir);
-            return;
-        }
-
-        if (DEBUG_PACKAGE_SCANNING) {
-            Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
-                    + " flags=0x" + Integer.toHexString(parseFlags));
-        }
-
-        ParallelPackageParser parallelPackageParser =
-                new ParallelPackageParser(packageParser, executorService);
-
-        // Submit files for parsing in parallel
-        int fileCount = 0;
-        for (File file : files) {
-            final boolean isPackage = (isApkFile(file) || file.isDirectory())
-                    && !PackageInstallerService.isStageName(file.getName());
-            if (!isPackage) {
-                // Ignore entries which are not packages
-                continue;
-            }
-            parallelPackageParser.submit(file, parseFlags);
-            fileCount++;
-        }
-
-        // Process results one by one
-        for (; fileCount > 0; fileCount--) {
-            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
-            Throwable throwable = parseResult.throwable;
-            int errorCode = PackageManager.INSTALL_SUCCEEDED;
-            String errorMsg = null;
-
-            if (throwable == null) {
-                // TODO(toddke): move lower in the scan chain
-                // Static shared libraries have synthetic package names
-                if (parseResult.parsedPackage.isStaticSharedLibrary()) {
-                    renameStaticSharedLibraryPackage(parseResult.parsedPackage);
-                }
-                try {
-                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
-                            currentTime, null);
-                } catch (PackageManagerException e) {
-                    errorCode = e.error;
-                    errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
-                    Slog.w(TAG, errorMsg);
-                }
-            } else if (throwable instanceof PackageManagerException) {
-                PackageManagerException e = (PackageManagerException) throwable;
-                errorCode = e.error;
-                errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
-                Slog.w(TAG, errorMsg);
-            } else {
-                throw new IllegalStateException("Unexpected exception occurred while parsing "
-                        + parseResult.scanFile, throwable);
-            }
-
-            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
-                mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
-            }
-
-            // Delete invalid userdata apps
-            if ((scanFlags & SCAN_AS_SYSTEM) == 0
-                    && errorCode != PackageManager.INSTALL_SUCCEEDED) {
-                logCriticalInfo(Log.WARN,
-                        "Deleting invalid package at " + parseResult.scanFile);
-                removeCodePathLI(parseResult.scanFile);
-            }
-        }
-    }
-
     public static void reportSettingsProblem(int priority, String msg) {
         logCriticalInfo(priority, msg);
     }
 
-    private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
-            boolean forceCollect, boolean skipVerify) throws PackageManagerException {
-        // When upgrading from pre-N MR1, verify the package time stamp using the package
-        // directory and not the APK file.
-        final long lastModifiedTime = mIsPreNMR1Upgrade
-                ? new File(parsedPackage.getPath()).lastModified()
-                : getLastModifiedTime(parsedPackage);
-        final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
-        if (ps != null && !forceCollect
-                && ps.getPathString().equals(parsedPackage.getPath())
-                && ps.timeStamp == lastModifiedTime
-                && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
-                && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
-            if (ps.signatures.mSigningDetails.getSignatures() != null
-                    && ps.signatures.mSigningDetails.getSignatures().length != 0
-                    && ps.signatures.mSigningDetails.getSignatureSchemeVersion()
-                            != SignatureSchemeVersion.UNKNOWN) {
-                // Optimization: reuse the existing cached signing data
-                // if the package appears to be unchanged.
-                parsedPackage.setSigningDetails(
-                        new SigningDetails(ps.signatures.mSigningDetails));
-                return;
-            }
 
-            Slog.w(TAG, "PackageSetting for " + ps.name
-                    + " is missing signatures.  Collecting certs again to recover them.");
-        } else {
-            Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs"
-                    + (forceCollect ? " (forced)" : ""));
-        }
 
-        try {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
-            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
-            final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
-                    input, parsedPackage, skipVerify);
-            if (result.isError()) {
-                throw new PackageManagerException(
-                        result.getErrorCode(), result.getErrorMessage(), result.getException());
-            }
-            parsedPackage.setSigningDetails(result.getResult());
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-    }
 
-    /**
-     * Clear the package profile if this was an upgrade and the package
-     * version was updated.
-     */
-    private void maybeClearProfilesForUpgradesLI(
-            @Nullable PackageSetting originalPkgSetting,
-            @NonNull AndroidPackage pkg) {
-        if (originalPkgSetting == null || !isDeviceUpgrading()) {
-          return;
-        }
-        if (originalPkgSetting.versionCode == pkg.getVersionCode()) {
-          return;
-        }
-
-        clearAppProfilesLIF(pkg);
-        if (DEBUG_INSTALL) {
-            Slog.d(TAG, originalPkgSetting.name
-                  + " clear profile due to version change "
-                  + originalPkgSetting.versionCode + " != "
-                  + pkg.getVersionCode());
-        }
-    }
 
     /**
      *  Traces a package scan.
      *  @see #scanPackageLI(File, int, int, long, UserHandle)
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
+    AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
             int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
@@ -11877,318 +10791,9 @@
             renameStaticSharedLibraryPackage(parsedPackage);
         }
 
-        return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
-    }
-
-    /**
-     * Returns if forced apk verification can be skipped for the whole package, including splits.
-     */
-    private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
-        if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
-            return false;
-        }
-        // TODO: Allow base and splits to be verified individually.
-        String[] splitCodePaths = pkg.getSplitCodePaths();
-        if (!ArrayUtils.isEmpty(splitCodePaths)) {
-            for (int i = 0; i < splitCodePaths.length; i++) {
-                if (!canSkipForcedApkVerification(splitCodePaths[i])) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
-     * whether the apk contains signed root hash.  Note that the signer's certificate still needs to
-     * match one in a trusted source, and should be done separately.
-     */
-    private boolean canSkipForcedApkVerification(String apkPath) {
-        if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
-            return VerityUtils.hasFsverity(apkPath);
-        }
-
-        try {
-            final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
-            if (rootHashObserved == null) {
-                return false;  // APK does not contain Merkle tree root hash.
-            }
-            synchronized (mInstallLock) {
-                // Returns whether the observed root hash matches what kernel has.
-                mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
-                return true;
-            }
-        } catch (InstallerException | IOException | DigestException |
-                NoSuchAlgorithmException e) {
-            Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
-        }
-        return false;
-    }
-
-    /**
-     * Adds a new package to the internal data structures during platform initialization.
-     * <p>After adding, the package is known to the system and available for querying.
-     * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
-     * etc...], additional checks are performed. Basic verification [such as ensuring
-     * matching signatures, checking version codes, etc...] occurs if the package is
-     * identical to a previously known package. If the package fails a signature check,
-     * the version installed on /data will be removed. If the version of the new package
-     * is less than or equal than the version on /data, it will be ignored.
-     * <p>Regardless of the package location, the results are applied to the internal
-     * structures and the package is made available to the rest of the system.
-     * <p>NOTE: The return value should be removed. It's the passed in package object.
-     */
-    @GuardedBy({"mInstallLock", "mLock"})
-    private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
-            @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
-            @Nullable UserHandle user)
-                    throws PackageManagerException {
-        final boolean scanSystemPartition =
-                (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
-        final String renamedPkgName;
-        final PackageSetting disabledPkgSetting;
-        final boolean isSystemPkgUpdated;
-        final boolean pkgAlreadyExists;
-        PackageSetting pkgSetting;
-
-        synchronized (mLock) {
-            renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
-            final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
-            if (realPkgName != null) {
-                ensurePackageRenamed(parsedPackage, renamedPkgName);
-            }
-            final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
-                    renamedPkgName);
-            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(
-                    parsedPackage.getPackageName());
-            pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
-            pkgAlreadyExists = pkgSetting != null;
-            final String disabledPkgName = pkgAlreadyExists
-                    ? pkgSetting.name : parsedPackage.getPackageName();
-            if (scanSystemPartition && !pkgAlreadyExists
-                    && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
-                // The updated-package data for /system apk remains inconsistently
-                // after the package data for /data apk is lost accidentally.
-                // To recover it, enable /system apk and install it as non-updated system app.
-                Slog.w(TAG, "Inconsistent package setting of updated system app for "
-                        + disabledPkgName + ". To recover it, enable the system app"
-                        + "and install it as non-updated system app.");
-                mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
-            }
-            disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
-            isSystemPkgUpdated = disabledPkgSetting != null;
-
-            if (DEBUG_INSTALL && isSystemPkgUpdated) {
-                Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
-            }
-
-            final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
-                    ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
-                            0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
-                    : null;
-            if (DEBUG_PACKAGE_SCANNING
-                    && (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
-                    && sharedUserSetting != null) {
-                Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
-                        + " (uid=" + sharedUserSetting.userId + "):"
-                        + " packages=" + sharedUserSetting.packages);
-            }
-
-            if (scanSystemPartition) {
-                if (isSystemPkgUpdated) {
-                    // we're updating the disabled package, so, scan it as the package setting
-                    boolean isPlatformPackage = mPlatformPackage != null
-                            && Objects.equals(mPlatformPackage.getPackageName(),
-                            parsedPackage.getPackageName());
-                    final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
-                            null, disabledPkgSetting /* pkgSetting */,
-                            null /* disabledPkgSetting */, null /* originalPkgSetting */,
-                            null, parseFlags, scanFlags, isPlatformPackage, user, null);
-                    applyPolicy(parsedPackage, scanFlags, mPlatformPackage, true);
-                    final ScanResult scanResult =
-                            scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
-                    if (scanResult.mExistingSettingCopied
-                            && scanResult.mRequest.mPkgSetting != null) {
-                        scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting);
-                    }
-                }
-            }
-        }
-
-        final boolean newPkgChangedPaths = pkgAlreadyExists
-                && !pkgSetting.getPathString().equals(parsedPackage.getPath());
-        final boolean newPkgVersionGreater =
-                pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
-        final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
-                && newPkgChangedPaths && newPkgVersionGreater;
-        if (isSystemPkgBetter) {
-            // The version of the application on /system is greater than the version on
-            // /data. Switch back to the application on /system.
-            // It's safe to assume the application on /system will correctly scan. If not,
-            // there won't be a working copy of the application.
-            synchronized (mLock) {
-                // just remove the loaded entries from package lists
-                mPackages.remove(pkgSetting.name);
-            }
-
-            logCriticalInfo(Log.WARN,
-                    "System package updated;"
-                    + " name: " + pkgSetting.name
-                    + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
-                    + "; " + pkgSetting.getPathString()
-                            + " --> " + parsedPackage.getPath());
-
-            final InstallArgs args = createInstallArgsForExisting(
-                    pkgSetting.getPathString(), getAppDexInstructionSets(
-                            pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
-            args.cleanUpResourcesLI();
-            synchronized (mLock) {
-                mSettings.enableSystemPackageLPw(pkgSetting.name);
-            }
-        }
-
-        // The version of the application on the /system partition is less than or
-        // equal to the version on the /data partition. Throw an exception and use
-        // the application already installed on the /data partition.
-        if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
-            // In the case of a skipped package, commitReconciledScanResultLocked is not called to
-            // add the object to the "live" data structures, so this is the final mutation step
-            // 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.hideAsFinal();
-            throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
-                    + " at " + parsedPackage.getPath() + " ignored: updated version "
-                    + pkgSetting.versionCode + " better than this "
-                    + parsedPackage.getLongVersionCode());
-        }
-
-        // Verify certificates against what was last scanned. Force re-collecting certificate in two
-        // special cases:
-        // 1) when scanning system, force re-collect only if system is upgrading.
-        // 2) when scannning /data, force re-collect only if the app is privileged (updated from
-        // preinstall, or treated as privileged, e.g. due to shared user ID).
-        final boolean forceCollect = scanSystemPartition ? mIsUpgrade
-                : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
-        if (DEBUG_VERIFY && forceCollect) {
-            Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
-        }
-
-        // Full APK verification can be skipped during certificate collection, only if the file is
-        // in verified partition, or can be verified on access (when apk verity is enabled). In both
-        // cases, only data in Signing Block is verified instead of the whole file.
-        // TODO(b/136132412): skip for Incremental installation
-        final boolean skipVerify = scanSystemPartition
-                || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
-        collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
-
-        // Reset profile if the application version is changed
-        maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
-
-        /*
-         * A new system app appeared, but we already had a non-system one of the
-         * same name installed earlier.
-         */
-        boolean shouldHideSystemApp = false;
-        // A new application appeared on /system, but, we already have a copy of
-        // the application installed on /data.
-        if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
-                && !pkgSetting.isSystem()) {
-
-            if (!parsedPackage.getSigningDetails()
-                    .checkCapability(pkgSetting.signatures.mSigningDetails,
-                    SigningDetails.CertCapabilities.INSTALLED_DATA)
-                            && !pkgSetting.signatures.mSigningDetails.checkCapability(
-                                    parsedPackage.getSigningDetails(),
-                                    SigningDetails.CertCapabilities.ROLLBACK)) {
-                logCriticalInfo(Log.WARN,
-                        "System package signature mismatch;"
-                        + " name: " + pkgSetting.name);
-                try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
-                        parsedPackage.getPackageName(),
-                        "scanPackageInternalLI")) {
-                    deletePackageLIF(parsedPackage.getPackageName(), null, true,
-                            mUserManager.getUserIds(), 0, null, false);
-                }
-                pkgSetting = null;
-            } else if (newPkgVersionGreater) {
-                // The application on /system is newer than the application on /data.
-                // Simply remove the application on /data [keeping application data]
-                // and replace it with the version on /system.
-                logCriticalInfo(Log.WARN,
-                        "System package enabled;"
-                                + " name: " + pkgSetting.name
-                                + "; " + pkgSetting.versionCode + " --> "
-                                + parsedPackage.getLongVersionCode()
-                                + "; " + pkgSetting.getPathString() + " --> "
-                                + parsedPackage.getPath());
-                InstallArgs args = createInstallArgsForExisting(
-                        pkgSetting.getPathString(), getAppDexInstructionSets(
-                                pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
-                synchronized (mInstallLock) {
-                    args.cleanUpResourcesLI();
-                }
-            } else {
-                // The application on /system is older than the application on /data. Hide
-                // the application on /system and the version on /data will be scanned later
-                // and re-added like an update.
-                shouldHideSystemApp = true;
-                logCriticalInfo(Log.INFO,
-                        "System package disabled;"
-                                + " name: " + pkgSetting.name
-                                + "; old: " + pkgSetting.getPathString() + " @ "
-                                + pkgSetting.versionCode
-                                + "; new: " + parsedPackage.getPath() + " @ "
-                                + parsedPackage.getPath());
-            }
-        }
-
-        final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
-                | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
-        if (scanResult.mSuccess) {
-            synchronized (mLock) {
-                boolean appIdCreated = false;
-                try {
-                    final String pkgName = scanResult.mPkgSetting.name;
-                    final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
-                            new ReconcileRequest(
-                                    Collections.singletonMap(pkgName, scanResult),
-                                    mSharedLibraries,
-                                    mPackages,
-                                    Collections.singletonMap(
-                                            pkgName, getSettingsVersionForPackage(parsedPackage)),
-                                    Collections.singletonMap(pkgName,
-                                            getSharedLibLatestVersionSetting(scanResult))),
-                            mSettings.getKeySetManagerService(), mInjector);
-                    appIdCreated = optimisticallyRegisterAppId(scanResult);
-                    commitReconciledScanResultLocked(
-                            reconcileResult.get(pkgName), mUserManager.getUserIds());
-                } catch (PackageManagerException e) {
-                    if (appIdCreated) {
-                        cleanUpAppIdCreation(scanResult);
-                    }
-                    throw e;
-                }
-            }
-        }
-
-        if (shouldHideSystemApp) {
-            synchronized (mLock) {
-                mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
-            }
-        }
-        if (mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) {
-            if (pkgSetting != null && pkgSetting.isPackageLoading()) {
-                // Continue monitoring loading progress of active incremental packages
-                final IncrementalStatesCallback incrementalStatesCallback =
-                        new IncrementalStatesCallback(parsedPackage.getPackageName(), this);
-                pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
-                mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
-                        new IncrementalProgressListener(parsedPackage.getPackageName(), this));
-            }
-        }
-        return scanResult.mPkgSetting.pkg;
+        final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+        return helper.addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user,
+                mPlatformPackage, mIsUpgrade, mIsPreNMR1Upgrade);
     }
 
     // TODO:(b/135203078): Move to parsing
@@ -13152,7 +11757,7 @@
         }
     }
 
-    private void clearAppProfilesLIF(AndroidPackage pkg) {
+    void clearAppProfilesLIF(AndroidPackage pkg) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
@@ -13221,7 +11826,7 @@
     }
 
     @GuardedBy("mLock")
-    private void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
+    void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
             @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
             Map<String, AndroidPackage> availablePackages)
             throws PackageManagerException {
@@ -13528,10 +12133,6 @@
         }
     }
 
-
-
-
-
     /**
      * Returns the actual scan flags depending upon the state of the other settings.
      * <p>Updated system applications will not have the following flags set
@@ -13635,12 +12236,12 @@
     // method. Also, we need to solve the problem of potentially creating a new shared user
     // setting. That can probably be done later and patch things up after the fact.
     @GuardedBy({"mInstallLock", "mLock"})
-    private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
+    ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
 
         final String renamedPkgName = mSettings.getRenamedPackageLPr(
-                parsedPackage.getRealPackage());
+                AndroidPackageUtils.getRealPackageOrNull(parsedPackage));
         final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
         if (realPkgName != null) {
             ensurePackageRenamed(parsedPackage, renamedPkgName);
@@ -13699,10 +12300,10 @@
      */
     boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
             throws PackageManagerException {
-        if (!result.mExistingSettingCopied) {
+        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.mPkgSetting);
+            return mSettings.registerAppIdLPw(result.mPkgSetting, result.mNeedsNewAppId);
         }
         return false;
     }
@@ -13760,7 +12361,8 @@
         } else {
             pkgSetting = result.mPkgSetting;
             if (originalPkgSetting != null) {
-                mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(),
+                mSettings.addRenamedPackageLPw(
+                        AndroidPackageUtils.getRealPackageOrNull(parsedPackage),
                         originalPkgSetting.name);
                 mTransferredPackages.add(originalPkgSetting.name);
             } else {
@@ -13848,10 +12450,10 @@
      * <p>This may differ from the package's actual name if the application has already
      * been installed under one of this package's original names.
      */
-    private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
+    static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
         if (isPackageRenamed(pkg, renamedPkgName)) {
-            return pkg.getRealPackage();
+            return AndroidPackageUtils.getRealPackageOrNull(pkg);
         }
         return null;
     }
@@ -13870,7 +12472,7 @@
      * shared user [if any].
      */
     @GuardedBy("mLock")
-    private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
+    @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
         if (isPackageRenamed(pkg, renamedPkgName)) {
             return null;
@@ -13909,7 +12511,7 @@
      * <p>When we've already installed the package under an original name, update
      * the new package so we can continue to have the old name.
      */
-    private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
+    static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
             @NonNull String renamedPackageName) {
         if (!parsedPackage.getOriginalPackages().contains(renamedPackageName)
                 || parsedPackage.getPackageName().equals(renamedPackageName)) {
@@ -14022,7 +12624,7 @@
     @GuardedBy("mInstallLock")
     @VisibleForTesting
     @NonNull
-    static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+    ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
             Injector injector,
             boolean isUnderFactoryTest, long currentTime)
             throws PackageManagerException {
@@ -14072,15 +12674,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;
@@ -14111,7 +12723,7 @@
                     destCodeFile, parsedPackage.getNativeLibraryRootDir(),
                     AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
                     AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
-                    parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user,
+                    parsedPackage.getLongVersionCode(), pkgFlags, pkgPrivateFlags, user,
                     true /*allowInstall*/, instantApp, virtualPreload,
                     UserManagerService.getInstance(), usesStaticLibraries,
                     parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(),
@@ -14163,11 +12775,8 @@
             pkgSetting.getPkgState().setUpdatedSystemApp(true);
         }
 
-        parsedPackage
-                .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
-                        injector.getCompatibility()))
-                .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
-                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));
+        parsedPackage.setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
+                        injector.getCompatibility()));
 
         if (parsedPackage.isSystem()) {
             configurePackageComponents(parsedPackage);
@@ -14356,7 +12965,8 @@
         }
 
         return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
-                !createNewPackage /* existingSettingCopied */, staticSharedLibraryInfo,
+                !createNewPackage /* existingSettingCopied */,
+                leavingSharedUser /* needsNewAppId */, staticSharedLibraryInfo,
                 dynamicSharedLibraryInfos);
     }
 
@@ -14414,7 +13024,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,
+    static void applyPolicy(ParsedPackage parsedPackage,
             final @ScanFlags int scanFlags, AndroidPackage platformPkg,
             boolean isUpdatedSystemApp) {
         if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
@@ -14464,7 +13074,6 @@
         if (!parsedPackage.isSystem()) {
             // Only system apps can use these features.
             parsedPackage.clearOriginalPackages()
-                    .setRealPackage(null)
                     .clearAdoptPermissions();
         }
 
@@ -14808,7 +13417,7 @@
                     // If the target is already installed or 'overlay-config-signature' tag in
                     // SystemConfig is set, check this here to augment the last line of defense
                     // which is OMS.
-                    if (pkg.getOverlayTargetName() == null) {
+                    if (pkg.getOverlayTargetOverlayableName() == null) {
                         final PackageSetting targetPkgSetting =
                                 mSettings.getPackageLPr(pkg.getOverlayTarget());
                         if (targetPkgSetting != null) {
@@ -14984,11 +13593,8 @@
 
                 // The instance stored in PackageManagerService is special cased to be non-user
                 // specific, so initialize all the needed fields here.
-                mAndroidApplication = pkg.toAppInfoWithoutState();
-                mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
-                mAndroidApplication.privateFlags =
-                        PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
-                mAndroidApplication.initForUser(UserHandle.USER_SYSTEM);
+                mAndroidApplication = PackageInfoUtils.generateApplicationInfo(pkg, 0,
+                        new PackageUserState(), UserHandle.USER_SYSTEM, pkgSetting);
 
                 if (!mResolverReplaced) {
                     mResolveActivity.applicationInfo = mAndroidApplication;
@@ -15137,11 +13743,8 @@
 
             // The instance created in PackageManagerService is special cased to be non-user
             // specific, so initialize all the needed fields here.
-            ApplicationInfo appInfo = pkg.toAppInfoWithoutState();
-            appInfo.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
-            appInfo.privateFlags =
-                    PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
-            appInfo.initForUser(UserHandle.USER_SYSTEM);
+            ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0,
+                    new PackageUserState(), UserHandle.USER_SYSTEM, pkgSetting);
 
             // Set up information for custom user intent resolution activity.
             mResolveActivity.applicationInfo = appInfo;
@@ -15700,8 +14303,7 @@
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
-            boolean suspended) {
+    void sendPackagesSuspendedForUser(String intent, String[] pkgList, int[] uidList, int userId) {
         final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
         final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
         final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
@@ -15742,11 +14344,8 @@
             extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray());
             final SparseArray<int[]> allowList = allowListsToSend.get(i).size() == 0
                     ? null : allowListsToSend.get(i);
-            sendPackageBroadcast(
-                    suspended ? Intent.ACTION_PACKAGES_SUSPENDED
-                            : Intent.ACTION_PACKAGES_UNSUSPENDED,
-                    null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
-                    userIds, null, allowList, null);
+            sendPackageBroadcast(intent, null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null,
+                    null, userIds, null, allowList, null);
         }
     }
 
@@ -16060,6 +14659,8 @@
 
         final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
         final IntArray changedUids = new IntArray(packageNames.length);
+        final List<String> modifiedPackagesList = new ArrayList<>(packageNames.length);
+        final IntArray modifiedUids = new IntArray(packageNames.length);
         final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
         final boolean[] canSuspend = suspended ? canSuspendPackageForUserInternal(packageNames,
                 userId) : null;
@@ -16087,13 +14688,14 @@
                 unactionedPackages.add(packageName);
                 continue;
             }
-            boolean packageUnsuspended;
+            final boolean packageUnsuspended;
+            final boolean packageModified;
             synchronized (mLock) {
                 if (suspended) {
-                    pkgSetting.addOrUpdateSuspension(callingPackage, dialogInfo, appExtras,
-                            launcherExtras, userId);
+                    packageModified = pkgSetting.addOrUpdateSuspension(callingPackage,
+                            dialogInfo, appExtras, launcherExtras, userId);
                 } else {
-                    pkgSetting.removeSuspension(callingPackage, userId);
+                    packageModified = pkgSetting.removeSuspension(callingPackage, userId);
                 }
                 packageUnsuspended = !suspended && !pkgSetting.getSuspended(userId);
             }
@@ -16101,18 +14703,29 @@
                 changedPackagesList.add(packageName);
                 changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
             }
+            if (packageModified) {
+                modifiedPackagesList.add(packageName);
+                modifiedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+            }
         }
 
         if (!changedPackagesList.isEmpty()) {
-            final String[] changedPackages = changedPackagesList.toArray(
-                    new String[changedPackagesList.size()]);
-            sendPackagesSuspendedForUser(changedPackages, changedUids.toArray(), userId, suspended);
+            final String[] changedPackages = changedPackagesList.toArray(new String[0]);
+            sendPackagesSuspendedForUser(
+                    suspended ? Intent.ACTION_PACKAGES_SUSPENDED
+                              : Intent.ACTION_PACKAGES_UNSUSPENDED,
+                    changedPackages, changedUids.toArray(), userId);
             sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, userId);
             synchronized (mLock) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
         }
-        return unactionedPackages.toArray(new String[unactionedPackages.size()]);
+        // Send the suspension changed broadcast to ensure suspension state is not stale.
+        if (!modifiedPackagesList.isEmpty()) {
+            sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+                    modifiedPackagesList.toArray(new String[0]), modifiedUids.toArray(), userId);
+        }
+        return unactionedPackages.toArray(new String[0]);
     }
 
     @Override
@@ -16241,7 +14854,8 @@
             final String[] packageArray = unsuspendedPackages.toArray(
                     new String[unsuspendedPackages.size()]);
             sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
-            sendPackagesSuspendedForUser(packageArray, unsuspendedUids.toArray(), userId, false);
+            sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
+                    packageArray, unsuspendedUids.toArray(), userId);
         }
     }
 
@@ -16520,30 +15134,6 @@
         return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
     }
 
-
-    /**
-     * Get the default verification agent response code.
-     *
-     * @return default verification response code
-     */
-    private int getDefaultVerificationResponse(UserHandle user) {
-        if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
-            return PackageManager.VERIFICATION_REJECT;
-        }
-        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
-                DEFAULT_VERIFICATION_RESPONSE);
-    }
-
-    /**
-     * Get the default integrity verification response code.
-     */
-    private int getDefaultIntegrityVerificationResponse() {
-        // 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 PackageManager.VERIFICATION_REJECT;
-    }
-
     @Deprecated
     @Override
     public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
@@ -16614,17 +15204,6 @@
         }
     }
 
-    /**
-     * Get the "allow unknown sources" setting.
-     *
-     * @return the current "allow unknown sources" setting
-     */
-    private int getUnknownSourcesSettings() {
-        return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
-                android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
-                -1);
-    }
-
     @Override
     public void setInstallerPackageName(String targetPackage, String installerPackageName) {
         final int callingUid = Binder.getCallingUid();
@@ -16941,7 +15520,7 @@
         });
     }
 
-    private void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
+    void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
             int[] userIds, int[] instantUserIds) {
         sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
                 installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
@@ -16980,19 +15559,8 @@
         return new File(firstLevelDir, packageName + "-" + suffix);
     }
 
-    private void removeNativeBinariesLI(PackageSetting ps) {
-        if (ps != null) {
-            NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
-        }
-    }
-
     @GuardedBy("mLock")
-    private void enableSystemPackageLPw(AndroidPackage pkg) {
-        mSettings.enableSystemPackageLPw(pkg.getPackageName());
-    }
-
-    @GuardedBy("mLock")
-    static Map<String, ReconciledPackage> reconcilePackagesLocked(
+    Map<String, ReconciledPackage> reconcilePackagesLocked(
             final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
             throws ReconcileFailure {
         final Map<String, ScanResult> scannedPackages = request.mScannedPackages;
@@ -17868,7 +16436,10 @@
                             Slog.i(TAG, "Enabling system stub after removal; pkg: "
                                     + stubPkg.getPackageName());
                         }
-                        enableCompressedPackage(stubPkg, stubPs);
+                        final InitAndSystemPackageHelper helper =
+                                new InitAndSystemPackageHelper(this);
+                        helper.enableCompressedPackage(stubPkg, stubPs, mDefParseFlags,
+                                mDirsToScanAsSystem);
                     } else if (DEBUG_COMPRESSION) {
                         Slog.i(TAG, "System stub disabled for all users, leaving uncompressed "
                                 + "after removal; pkg: " + stubPkg.getPackageName());
@@ -17887,7 +16458,7 @@
      * make sure this flag is set for partially installed apps. If not its meaningless to
      * delete a partially installed application.
      */
-    private void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
+    void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
             PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
         String packageName = deletedPs.name;
         if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
@@ -17932,7 +16503,8 @@
                 synchronized (mLock) {
                     mDomainVerificationManager.clearPackage(deletedPs.name);
                     mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
-                    mAppsFilter.removePackage(getPackageSetting(packageName));
+                    mAppsFilter.removePackage(getPackageSetting(packageName),
+                            false /* isReplace */);
                     removedAppId = mSettings.removePackageLPw(packageName);
                     if (outInfo != null) {
                         outInfo.mRemovedAppId = removedAppId;
@@ -18010,181 +16582,7 @@
         return null;
     }
 
-    /*
-     * Tries to delete system package.
-     */
-    private void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs,
-            @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
-            boolean writeSettings)
-            throws SystemDeleteException {
-        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.mDisabledPs;
-        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
-                + " disabledPs=" + disabledPs);
-        Slog.d(TAG, "Deleting system pkg from data partition");
-
-        if (DEBUG_REMOVE) {
-            if (applyUserRestrictions) {
-                Slog.d(TAG, "Remembering install states:");
-                for (int userId : allUserHandles) {
-                    final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId);
-                    Slog.d(TAG, "   u=" + userId + " inst=" + finstalled);
-                }
-            }
-        }
-
-        if (outInfo != null) {
-            // Delete the updated package
-            outInfo.mIsRemovedPackageSystemUpdate = true;
-        }
-
-        if (disabledPs.versionCode < deletedPs.versionCode) {
-            // Delete data for downgrades
-            flags &= ~PackageManager.DELETE_KEEP_DATA;
-        } else {
-            // Preserve data by setting flag
-            flags |= PackageManager.DELETE_KEEP_DATA;
-        }
-
-        deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
-                outInfo, writeSettings);
-
-        // writer
-        synchronized (mLock) {
-            // NOTE: The system package always needs to be enabled; even if it's for
-            // a compressed stub. If we don't, installing the system package fails
-            // during scan [scanning checks the disabled packages]. We will reverse
-            // this later, after we've "installed" the stub.
-            // Reinstate the old system package
-            enableSystemPackageLPw(disabledPs.pkg);
-            // Remove any native libraries from the upgraded package.
-            removeNativeBinariesLI(deletedPs);
-        }
-
-        // Install the system package
-        if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
-        try {
-            installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
-                    outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
-        } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
-                    + e.getMessage());
-            // TODO(patb): can we avoid this; throw would come from scan...
-            throw new SystemDeleteException(e);
-        } finally {
-            if (disabledPs.pkg.isStub()) {
-                // We've re-installed the stub; make sure it's disabled here. If package was
-                // originally enabled, we'll install the compressed version of the application
-                // and re-enable it afterward.
-                final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName());
-                if (stubPs != null) {
-                    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");
-                        }
-                    } else if (userId >= UserHandle.USER_SYSTEM) {
-                        stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Installs a package that's already on the system partition.
-     */
-    private void installPackageFromSystemLIF(@NonNull String codePathString,
-            @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
-            throws PackageManagerException {
-        final File codePath = new File(codePathString);
-        @ParseFlags int parseFlags =
-                mDefParseFlags
-                | ParsingPackageUtils.PARSE_MUST_BE_APK
-                | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
-        @ScanFlags int scanFlags = SCAN_AS_SYSTEM;
-        for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
-            ScanPartition partition = mDirsToScanAsSystem.get(i);
-            if (partition.containsFile(codePath)) {
-                scanFlags |= partition.scanFlag;
-                if (partition.containsPrivApp(codePath)) {
-                    scanFlags |= SCAN_AS_PRIVILEGED;
-                }
-                break;
-            }
-        }
-
-        final AndroidPackage pkg =
-                scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
-
-        PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
-
-        try {
-            // update shared libraries for the newly re-installed system package
-            updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
-                    Collections.unmodifiableMap(mPackages));
-        } catch (PackageManagerException e) {
-            Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
-        }
-
-        prepareAppDataAfterInstallLIF(pkg);
-
-        // writer
-        synchronized (mLock) {
-            PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
-
-            final boolean applyUserRestrictions = origUserHandles != null;
-            if (applyUserRestrictions) {
-                boolean installedStateChanged = false;
-                if (DEBUG_REMOVE) {
-                    Slog.d(TAG, "Propagating install state across reinstall");
-                }
-                for (int userId : allUserHandles) {
-                    final boolean installed = ArrayUtils.contains(origUserHandles, userId);
-                    if (DEBUG_REMOVE) {
-                        Slog.d(TAG, "    user " + userId + " => " + installed);
-                    }
-                    if (installed != ps.getInstalled(userId)) {
-                        installedStateChanged = true;
-                    }
-                    ps.setInstalled(installed, userId);
-                    if (installed) {
-                        ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
-                    }
-                }
-                // Regardless of writeSettings we need to ensure that this restriction
-                // state propagation is persisted
-                mSettings.writeAllUsersPackageRestrictionsLPr();
-                if (installedStateChanged) {
-                    mSettings.writeKernelMappingLPr(ps);
-                }
-            }
-
-            // The method below will take care of removing obsolete permissions and granting
-            // install permissions.
-            mPermissionManager.onPackageInstalled(pkg,
-                    PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
-                    UserHandle.USER_ALL);
-            for (final int userId : allUserHandles) {
-                if (applyUserRestrictions) {
-                    mSettings.writePermissionStateForUserLPr(userId, false);
-                }
-            }
-
-            // can downgrade to reader here
-            if (writeSettings) {
-                writeSettingsLPrTEMP();
-            }
-        }
-    }
-
-    private void deleteInstalledPackageLIF(PackageSetting ps,
+    void deleteInstalledPackageLIF(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
             PackageRemovedInfo outInfo, boolean writeSettings) {
         synchronized (mLock) {
@@ -18289,7 +16687,7 @@
     /*
      * This method handles package deletion in general
      */
-    private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
+    boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
             boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
             PackageRemovedInfo outInfo, boolean writeSettings) {
         final DeletePackageAction action;
@@ -18384,7 +16782,9 @@
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
             // When an updated system application is deleted we delete the existing resources
             // as well and fall back to existing code in system partition
-            deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);
+            final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+            helper.deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo,
+                    writeSettings, mDefParseFlags, mDirsToScanAsSystem);
         } else {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
             deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
@@ -18594,7 +16994,7 @@
 
         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
         final int flags;
-        if (StorageManager.isUserKeyUnlocked(userId)) {
+        if (umInternal.isUserUnlockingOrUnlocked(userId)) {
             flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
         } else if (umInternal.isUserRunning(userId)) {
             flags = StorageManager.FLAG_STORAGE_DE;
@@ -18992,7 +17392,7 @@
         mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId);
     }
 
-    private void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
+    void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
             @UserIdInt int userId) {
         // We may also need to apply pending (restored) runtime permission grants
         // within these users.
@@ -19784,7 +18184,9 @@
         if (callingPackage == null) {
             callingPackage = Integer.toString(Binder.getCallingUid());
         }
-        setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage);
+
+        setEnabledSettings(List.of(new ComponentEnabledSetting(appPackageName, newState, flags)),
+                userId, callingPackage);
     }
 
     @Override
@@ -19881,216 +18283,272 @@
     public void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags, int userId) {
         if (!mUserManager.exists(userId)) return;
-        setEnabledSetting(componentName.getPackageName(),
-                componentName.getClassName(), newState, flags, userId, null);
+
+        setEnabledSettings(List.of(new ComponentEnabledSetting(componentName, newState, flags)),
+                userId, null /* callingPackage */);
     }
 
-    private void setEnabledSetting(final String packageName, String className, int newState,
-            final int flags, int userId, String callingPackage) {
-        if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
-              || newState == COMPONENT_ENABLED_STATE_ENABLED
-              || newState == COMPONENT_ENABLED_STATE_DISABLED
-              || newState == COMPONENT_ENABLED_STATE_DISABLED_USER
-              || newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
-            throw new IllegalArgumentException("Invalid new component state: "
-                    + newState);
+    @Override
+    public void setComponentEnabledSettings(List<ComponentEnabledSetting> settings, int userId) {
+        if (!mUserManager.exists(userId)) return;
+        if (settings == null || settings.isEmpty()) {
+            throw new IllegalArgumentException("The list of enabled settings is empty");
         }
+
+        setEnabledSettings(settings, userId, null /* callingPackage */);
+    }
+
+    private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId,
+            String callingPackage) {
         final int callingUid = Binder.getCallingUid();
-        final int permission;
-        if (callingUid == Process.SYSTEM_UID) {
-            permission = PackageManager.PERMISSION_GRANTED;
-        } else {
-            permission = mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
-        }
         enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
                 true /* checkShell */, "set enabled");
-        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
-        boolean sendNow = false;
-        boolean isApp = (className == null);
-        String componentName = isApp ? packageName : className;
-        ArrayList<String> components;
 
-        final boolean isCallerTargetApp = ArrayUtils.contains(
-                getPackagesForUid(callingUid), packageName);
-        final PackageSetting pkgSetting;
+        final int targetSize = settings.size();
+        for (int i = 0; i < targetSize; i++) {
+            final int newState = settings.get(i).getEnabledState();
+            if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
+                    || newState == COMPONENT_ENABLED_STATE_ENABLED
+                    || newState == COMPONENT_ENABLED_STATE_DISABLED
+                    || newState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                    || newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
+                throw new IllegalArgumentException("Invalid new component state: " + newState);
+            }
+        }
+        if (targetSize > 1) {
+            final ArraySet<String> checkDuplicatedPackage = new ArraySet<>();
+            final ArraySet<ComponentName> checkDuplicatedComponent = new ArraySet<>();
+            final ArrayMap<String, Integer> checkConflictFlag = new ArrayMap<>();
+            for (int i = 0; i < targetSize; i++) {
+                final ComponentEnabledSetting setting = settings.get(i);
+                final String packageName = setting.getPackageName();
+                if (setting.isComponent()) {
+                    final ComponentName componentName = setting.getComponentName();
+                    if (checkDuplicatedComponent.contains(componentName)) {
+                        throw new IllegalArgumentException("The component " + componentName
+                                + " is duplicated");
+                    }
+                    checkDuplicatedComponent.add(componentName);
+
+                    // check if there is a conflict of the DONT_KILL_APP flag between components
+                    // in the package
+                    final Integer enabledFlags = checkConflictFlag.get(packageName);
+                    if (enabledFlags == null) {
+                        checkConflictFlag.put(packageName, setting.getEnabledFlags());
+                    } else if ((enabledFlags & PackageManager.DONT_KILL_APP)
+                            != (setting.getEnabledFlags() & PackageManager.DONT_KILL_APP)) {
+                        throw new IllegalArgumentException("A conflict of the DONT_KILL_APP flag "
+                                + "between components in the package " + packageName);
+                    }
+                } else {
+                    if (checkDuplicatedPackage.contains(packageName)) {
+                        throw new IllegalArgumentException("The package " + packageName
+                                + " is duplicated");
+                    }
+                    checkDuplicatedPackage.add(packageName);
+                }
+            }
+        }
+
+        final boolean allowedByPermission = mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE) == PERMISSION_GRANTED;
+        final boolean[] updateAllowed = new boolean[targetSize];
+        Arrays.fill(updateAllowed, true);
+
+        final Map<String, PackageSetting> pkgSettings = new ArrayMap<>(targetSize);
         // reader
         synchronized (mLock) {
-            pkgSetting = mSettings.getPackageLPr(packageName);
-            // Limit who can change which apps
-            if (!isCallerTargetApp) {
-                // Don't allow apps that don't have permission to modify other apps
+            // Checks for target packages
+            for (int i = 0; i < targetSize; i++) {
+                final ComponentEnabledSetting setting = settings.get(i);
+                final String packageName = setting.getPackageName();
+                if (pkgSettings.containsKey(packageName)) {
+                    // this package has verified
+                    continue;
+                }
+                final boolean isCallerTargetApp = ArrayUtils.contains(
+                        getPackagesForUid(callingUid), packageName);
+                final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+                // Limit who can change which apps
+                if (!isCallerTargetApp) {
+                    // Don't allow apps that don't have permission to modify other apps
+                    if (!allowedByPermission
+                            || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
+                        throw new SecurityException("Attempt to change component state; "
+                                + "pid=" + Binder.getCallingPid()
+                                + ", uid=" + callingUid
+                                + (!setting.isComponent() ? ", package=" + packageName
+                                        : ", component=" + setting.getComponentName()));
+                    }
+                    // Don't allow changing protected packages.
+                    if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+                        throw new SecurityException(
+                                "Cannot disable a protected package: " + packageName);
+                    }
+                }
+                if (pkgSetting == null) {
+                    throw new IllegalArgumentException(setting.isComponent()
+                            ? "Unknown component: " + setting.getComponentName()
+                            : "Unknown package: " + packageName);
+                }
+                if (callingUid == Process.SHELL_UID
+                        && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
+                    // Shell can only change whole packages between ENABLED and DISABLED_USER states
+                    // unless it is a test package.
+                    final int oldState = pkgSetting.getEnabled(userId);
+                    final int newState = setting.getEnabledState();
+                    if (!setting.isComponent()
+                            &&
+                            (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                                    || oldState == COMPONENT_ENABLED_STATE_DEFAULT
+                                    || oldState == COMPONENT_ENABLED_STATE_ENABLED)
+                            &&
+                            (newState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                                    || newState == COMPONENT_ENABLED_STATE_DEFAULT
+                                    || newState == COMPONENT_ENABLED_STATE_ENABLED)) {
+                        // ok
+                    } else {
+                        throw new SecurityException(
+                                "Shell cannot change component state for "
+                                        + setting.getComponentName() + " to " + newState);
+                    }
+                }
+                pkgSettings.put(packageName, pkgSetting);
+            }
+            // Checks for target components
+            for (int i = 0; i < targetSize; i++) {
+                final ComponentEnabledSetting setting = settings.get(i);
+                // skip if it's application
+                if (!setting.isComponent()) continue;
+
+                // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
+                // app details activity
+                final String packageName = setting.getPackageName();
+                final String className = setting.getClassName();
                 if (!allowedByPermission
-                        || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
-                    throw new SecurityException(
-                            "Attempt to change component state; "
-                                    + "pid=" + Binder.getCallingPid()
-                                    + ", uid=" + callingUid
-                                    + (className == null
-                                            ? ", package=" + packageName
-                                            : ", component=" + packageName + "/" + className));
+                        && PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    throw new SecurityException("Cannot disable a system-generated component");
                 }
-                // Don't allow changing protected packages.
-                if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
-                    throw new SecurityException(
-                            "Cannot disable a protected package: " + packageName);
-                }
-            }
-            if (pkgSetting == null) {
-                if (className == null) {
-                    throw new IllegalArgumentException("Unknown package: " + packageName);
-                }
-                throw new IllegalArgumentException(
-                        "Unknown component: " + packageName + "/" + className);
-            }
-        }
-
-        // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
-        // app details activity
-        if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)
-                && !allowedByPermission) {
-            throw new SecurityException("Cannot disable a system-generated component");
-        }
-
-        synchronized (mLock) {
-            if (callingUid == Process.SHELL_UID
-                    && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
-                // Shell can only change whole packages between ENABLED and DISABLED_USER states
-                // unless it is a test package.
-                int oldState = pkgSetting.getEnabled(userId);
-                if (className == null
-                        &&
-                        (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER
-                                || oldState == COMPONENT_ENABLED_STATE_DEFAULT
-                                || oldState == COMPONENT_ENABLED_STATE_ENABLED)
-                        &&
-                        (newState == COMPONENT_ENABLED_STATE_DISABLED_USER
-                                || newState == COMPONENT_ENABLED_STATE_DEFAULT
-                                || newState == COMPONENT_ENABLED_STATE_ENABLED)) {
-                    // ok
-                } else {
-                    throw new SecurityException(
-                            "Shell cannot change component state for " + packageName + "/"
-                                    + className + " to " + newState);
-                }
-            }
-        }
-        if (className == null) {
-            // We're dealing with an application/package level state change
-            synchronized (mLock) {
-                if (pkgSetting.getEnabled(userId) == newState) {
-                    // Nothing to do
-                    return;
-                }
-            }
-            // If we're enabling a system stub, there's a little more work to do.
-            // Prior to enabling the package, we need to decompress the APK(s) to the
-            // data partition and then replace the version on the system partition.
-            final AndroidPackage deletedPkg = pkgSetting.pkg;
-            final boolean isSystemStub = (deletedPkg != null)
-                    && deletedPkg.isStub()
-                    && deletedPkg.isSystem();
-            if (isSystemStub
-                    && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
-                            || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
-                if (!enableCompressedPackage(deletedPkg, pkgSetting)) {
-                    return;
-                }
-            }
-            if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
-                || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
-                // Don't care about who enables an app.
-                callingPackage = null;
-            }
-            synchronized (mLock) {
-                pkgSetting.setEnabled(newState, userId, callingPackage);
-                if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
-                        || newState == COMPONENT_ENABLED_STATE_DISABLED)
-                        && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
-                        == PERMISSION_GRANTED) {
-                    // This app should not generally be allowed to get disabled by the UI, but if it
-                    // ever does, we don't want to end up with some of the user's apps permanently
-                    // suspended.
-                    unsuspendForSuspendingPackage(packageName, userId);
-                    removeAllDistractingPackageRestrictions(userId);
-                }
-            }
-        } else {
-            synchronized (mLock) {
-                // We're dealing with a component level state change
-                // First, verify that this is a valid class name.
-                AndroidPackage pkg = pkgSetting.pkg;
+                // Verify that this is a valid class name.
+                final AndroidPackage pkg = pkgSettings.get(packageName).getPkg();
                 if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) {
-                    if (pkg != null &&
-                            pkg.getTargetSdkVersion() >=
-                                    Build.VERSION_CODES.JELLY_BEAN) {
+                    if (pkg != null
+                            && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) {
                         throw new IllegalArgumentException("Component class " + className
                                 + " does not exist in " + packageName);
                     } else {
                         Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
                                 + className + " does not exist in " + packageName);
+                        updateAllowed[i] = false;
                     }
                 }
-                switch (newState) {
-                    case COMPONENT_ENABLED_STATE_ENABLED:
-                        if (!pkgSetting.enableComponentLPw(className, userId)) {
-                            return;
-                        }
-                        break;
-                    case COMPONENT_ENABLED_STATE_DISABLED:
-                        if (!pkgSetting.disableComponentLPw(className, userId)) {
-                            return;
-                        }
-                        break;
-                    case COMPONENT_ENABLED_STATE_DEFAULT:
-                        if (!pkgSetting.restoreComponentLPw(className, userId)) {
-                            return;
-                        }
-                        break;
-                    default:
-                        Slog.e(TAG, "Invalid new component state: " + newState);
-                        return;
-                }
             }
         }
+
+        // More work for application enabled setting updates
+        for (int i = 0; i < targetSize; i++) {
+            final ComponentEnabledSetting setting = settings.get(i);
+            // skip if it's component
+            if (setting.isComponent()) continue;
+
+            final PackageSetting pkgSetting = pkgSettings.get(setting.getPackageName());
+            final int newState = setting.getEnabledState();
+            synchronized (mLock) {
+                if (pkgSetting.getEnabled(userId) == newState) {
+                    // Nothing to do
+                    updateAllowed[i] = false;
+                    continue;
+                }
+            }
+            // If we're enabling a system stub, there's a little more work to do.
+            // Prior to enabling the package, we need to decompress the APK(s) to the
+            // data partition and then replace the version on the system partition.
+            final AndroidPackage deletedPkg = pkgSetting.getPkg();
+            final boolean isSystemStub = (deletedPkg != null)
+                    && deletedPkg.isStub()
+                    && deletedPkg.isSystem();
+            if (isSystemStub
+                    && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                    || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
+                final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+                if (!helper.enableCompressedPackage(deletedPkg, pkgSetting, mDefParseFlags,
+                        mDirsToScanAsSystem)) {
+                    Slog.w(TAG, "Failed setApplicationEnabledSetting: failed to enable "
+                            + "commpressed package " + setting.getPackageName());
+                    updateAllowed[i] = false;
+                    continue;
+                }
+            }
+        }
+
+        // packageName -> list of components to send broadcasts now
+        final ArrayMap<String, ArrayList<String>> sendNowBroadcasts = new ArrayMap<>(targetSize);
         synchronized (mLock) {
-            if ((flags & PackageManager.SYNCHRONOUS) != 0) {
+            boolean scheduleBroadcastMessage = false;
+            boolean isSynchronous = false;
+            boolean anyChanged = false;
+
+            for (int i = 0; i < targetSize; i++) {
+                if (!updateAllowed[i]) {
+                    continue;
+                }
+                // update enabled settings
+                final ComponentEnabledSetting setting = settings.get(i);
+                final String packageName = setting.getPackageName();
+                if (!setEnabledSettingInternalLocked(pkgSettings.get(packageName), setting,
+                        userId, callingPackage)) {
+                    continue;
+                }
+                anyChanged = true;
+
+                if ((setting.getEnabledFlags() & PackageManager.SYNCHRONOUS) != 0) {
+                    isSynchronous = true;
+                }
+                // collect broadcast list for the package
+                final String componentName = setting.isComponent()
+                        ? setting.getClassName() : packageName;
+                ArrayList<String> componentList = sendNowBroadcasts.get(packageName);
+                if (componentList == null) {
+                    componentList = mPendingBroadcasts.get(userId, packageName);
+                }
+                final boolean newPackage = componentList == null;
+                if (newPackage) {
+                    componentList = new ArrayList<>();
+                }
+                if (!componentList.contains(componentName)) {
+                    componentList.add(componentName);
+                }
+                if ((setting.getEnabledFlags() & PackageManager.DONT_KILL_APP) == 0) {
+                    sendNowBroadcasts.put(packageName, componentList);
+                    // Purge entry from pending broadcast list if another one exists already
+                    // since we are sending one right away.
+                    mPendingBroadcasts.remove(userId, packageName);
+                } else {
+                    if (newPackage) {
+                        mPendingBroadcasts.put(userId, packageName, componentList);
+                    }
+                    scheduleBroadcastMessage = true;
+                }
+            }
+            if (!anyChanged) {
+                // nothing changed, return immediately
+                return;
+            }
+
+            if (isSynchronous) {
                 flushPackageRestrictionsAsUserInternalLocked(userId);
             } else {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
-            updateSequenceNumberLP(pkgSetting, new int[] { userId });
-            final long callingId = Binder.clearCallingIdentity();
-            try {
-                updateInstantAppInstallerLocked(packageName);
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
-            }
-            components = mPendingBroadcasts.get(userId, packageName);
-            final boolean newPackage = components == null;
-            if (newPackage) {
-                components = new ArrayList<>();
-            }
-            if (!components.contains(componentName)) {
-                components.add(componentName);
-            }
-            if ((flags&PackageManager.DONT_KILL_APP) == 0) {
-                sendNow = true;
-                // Purge entry from pending broadcast list if another one exists already
-                // since we are sending one right away.
-                mPendingBroadcasts.remove(userId, packageName);
-            } else {
-                if (newPackage) {
-                    mPendingBroadcasts.put(userId, packageName, components);
-                }
+            if (scheduleBroadcastMessage) {
                 if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
                     // Schedule a message - if it has been a "reasonably long time" since the
                     // service started, send the broadcast with a delay of one second to avoid
                     // delayed reactions from the receiver, else keep the default ten second delay
                     // to avoid extreme thrashing on service startup.
                     final long broadcastDelay = SystemClock.uptimeMillis() > mServiceStartWithDelay
-                                                ? BROADCAST_DELAY
-                                                : BROADCAST_DELAY_DURING_STARTUP;
+                            ? BROADCAST_DELAY
+                            : BROADCAST_DELAY_DURING_STARTUP;
                     mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, broadcastDelay);
                 }
             }
@@ -20098,16 +18556,78 @@
 
         final long callingId = Binder.clearCallingIdentity();
         try {
-            if (sendNow) {
-                int packageUid = UserHandle.getUid(userId, pkgSetting.appId);
-                sendPackageChangedBroadcast(packageName,
-                        (flags & PackageManager.DONT_KILL_APP) != 0, components, packageUid, null);
+            for (int i = 0; i < sendNowBroadcasts.size(); i++) {
+                final String packageName = sendNowBroadcasts.keyAt(i);
+                final ArrayList<String> components = sendNowBroadcasts.valueAt(i);
+                final int packageUid = UserHandle.getUid(
+                        userId, pkgSettings.get(packageName).appId);
+                sendPackageChangedBroadcast(packageName, false /* dontKillApp */,
+                        components, packageUid, null /* reason */);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
     }
 
+    private boolean setEnabledSettingInternalLocked(PackageSetting pkgSetting,
+            ComponentEnabledSetting setting, int userId, String callingPackage) {
+        final int newState = setting.getEnabledState();
+        final String packageName = setting.getPackageName();
+        boolean success = false;
+        if (!setting.isComponent()) {
+            // We're dealing with an application/package level state change
+            if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                    || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+                // Don't care about who enables an app.
+                callingPackage = null;
+            }
+            pkgSetting.setEnabled(newState, userId, callingPackage);
+            if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
+                    || newState == COMPONENT_ENABLED_STATE_DISABLED)
+                    && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+                    == PERMISSION_GRANTED) {
+                // This app should not generally be allowed to get disabled by the UI, but
+                // if it ever does, we don't want to end up with some of the user's apps
+                // permanently suspended.
+                unsuspendForSuspendingPackage(packageName, userId);
+                removeAllDistractingPackageRestrictions(userId);
+            }
+            success = true;
+        } else {
+            // We're dealing with a component level state change
+            final String className = setting.getClassName();
+            switch (newState) {
+                case COMPONENT_ENABLED_STATE_ENABLED:
+                    success = pkgSetting.enableComponentLPw(className, userId);
+                    break;
+                case COMPONENT_ENABLED_STATE_DISABLED:
+                    success = pkgSetting.disableComponentLPw(className, userId);
+                    break;
+                case COMPONENT_ENABLED_STATE_DEFAULT:
+                    success = pkgSetting.restoreComponentLPw(className, userId);
+                    break;
+                default:
+                    Slog.e(TAG, "Failed setComponentEnabledSetting: component "
+                            + packageName + "/" + className
+                            + " requested an invalid new component state: " + newState);
+                    break;
+            }
+        }
+        if (!success) {
+            return false;
+        }
+
+        updateSequenceNumberLP(pkgSetting, new int[] { userId });
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            updateInstantAppInstallerLocked(packageName);
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+
+        return true;
+    }
+
     @WorkerThread
     @Override
     public void flushPackageRestrictionsAsUser(int userId) {
@@ -20135,7 +18655,7 @@
         }
     }
 
-    private void sendPackageChangedBroadcast(String packageName,
+    void sendPackageChangedBroadcast(String packageName,
             boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason) {
         if (DEBUG_INSTALL)
             Log.v(TAG, "Sending package changed: package=" + packageName + " components="
@@ -20852,15 +19372,24 @@
 
         final String packageName = dumpState.getTargetPackageName();
         final boolean checkin = dumpState.isCheckIn();
+
+        // Return if the package doesn't exist.
+        if (packageName != null
+                && getPackageSetting(packageName) == null
+                && !mApexManager.isApexPackage(packageName)) {
+            pw.println("Unable to find package: " + packageName);
+            return;
+        }
+
         if (checkin) {
             pw.println("vers,1");
         }
 
         // reader
-        if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
-            if (!checkin) {
-                dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
-            }
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_VERSION)
+                && packageName == null) {
+            dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
         }
 
         if (!checkin
@@ -20891,7 +19420,8 @@
             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()) {
@@ -20912,14 +19442,16 @@
             }
         }
 
-        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) {
                 String verifierPackageName = verifierComponent.getPackageName();
                 if (!checkin) {
-                    if (dumpState.onTitlePrinted())
+                    if (dumpState.onTitlePrinted()) {
                         pw.println();
+                    }
                     pw.println("Domain Verifier:");
                     pw.print("  Using: ");
                     pw.print(verifierPackageName);
@@ -20939,11 +19471,13 @@
             }
         }
 
-        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();
             }
@@ -20953,12 +19487,7 @@
 
             synchronized (mAvailableFeatures) {
                 for (FeatureInfo feat : mAvailableFeatures.values()) {
-                    if (checkin) {
-                        pw.print("feat,");
-                        pw.print(feat.name);
-                        pw.print(",");
-                        pw.println(feat.version);
-                    } else {
+                    if (!checkin) {
                         pw.print("  ");
                         pw.print(feat.name);
                         if (feat.version > 0) {
@@ -20966,55 +19495,73 @@
                             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)) {
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
             dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
+                && packageName == null) {
             dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
             dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
-            mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+            synchronized (mLock) {
+                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);
             }
@@ -21029,7 +19576,8 @@
             }
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_QUERIES)) {
             dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
         }
 
@@ -21041,8 +19589,12 @@
             }
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
-            if (dumpState.onTitlePrinted()) pw.println();
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_CHANGES)
+                && packageName == null) {
+            if (dumpState.onTitlePrinted()) {
+                pw.println();
+            }
             pw.println("Package Changes:");
             synchronized (mLock) {
                 pw.print("  Sequence number="); pw.println(mChangedPackagesSequenceNumber);
@@ -21068,11 +19620,14 @@
             }
         }
 
-        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();
-
+            if (dumpState.onTitlePrinted()) {
+                pw.println();
+            }
             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
             ipw.println();
             ipw.println("Frozen packages:");
@@ -21089,9 +19644,12 @@
             ipw.decreaseIndent();
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
-            if (dumpState.onTitlePrinted()) pw.println();
-
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_VOLUMES)
+                && packageName == null) {
+            if (dumpState.onTitlePrinted()) {
+                pw.println();
+            }
             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
             ipw.println();
             ipw.println("Loaded volumes:");
@@ -21108,52 +19666,65 @@
             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)) {
-            if (dumpState.onTitlePrinted()) pw.println();
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
             dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
-            if (dumpState.onTitlePrinted()) pw.println();
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
             dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
-            if (dumpState.onTitlePrinted()) pw.println();
-            synchronized (mLock) {
-                mSettings.dumpReadMessagesLPr(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,");
             }
-            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();
+            if (dumpState.onTitlePrinted()) {
+                pw.println();
+            }
             mInstallerService.dump(new IndentingPrintWriter(pw, "  ", 120));
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_APEX)
+                && (packageName == null || mApexManager.isApexPackage(packageName))) {
             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();
+            if (dumpState.onTitlePrinted()) {
+                pw.println();
+            }
             pw.println("Per UID read timeouts:");
             pw.println("    Default timeouts flag: " + getDefaultTimeouts());
             pw.println("    Known digesters list flag: " + getKnownDigestersList());
@@ -21170,7 +19741,12 @@
             }
         }
 
-        if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
+        if (!checkin
+                && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)
+                && packageName == null) {
+            if (dumpState.onTitlePrinted()) {
+                pw.println();
+            }
             pw.println("Snapshot statistics");
             if (!mSnapshotEnabled) {
                 pw.println("  Snapshots disabled");
@@ -21387,7 +19963,7 @@
         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
         for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) {
             final int flags;
-            if (StorageManager.isUserKeyUnlocked(user.id)) {
+            if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
             } else if (umInternal.isUserRunning(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE;
@@ -21398,7 +19974,8 @@
             try {
                 sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
                 synchronized (mInstallLock) {
-                    reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */);
+                    reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */,
+                            null);
                 }
             } catch (IllegalStateException e) {
                 // Device was probably ejected, and we'll process that event momentarily
@@ -21587,21 +20164,32 @@
      * <p>
      * Verifies that directories exist and that ownership and labeling is
      * correct for all installed apps on all mounted volumes.
+     *
+     * @param reconciledPackages A set that will be populated with package names that have
+     *                           successfully had their data reconciled. Any package names already
+     *                           contained will be skipped. Because this must be mutable when
+     *                           non-null, it is typed {@link ArraySet} to prevent accidental
+     *                           usage of {@link Collections#emptySet()}. Null can be passed if the
+     *                           caller doesn't need this functionality.
      */
-    void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
+    @NonNull
+    void reconcileAppsData(int userId, int flags, boolean migrateAppsData,
+            @Nullable ArraySet<String> reconciledPackages) {
         final StorageManager storage = mInjector.getSystemService(StorageManager.class);
         for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
             final String volumeUuid = vol.getFsUuid();
             synchronized (mInstallLock) {
-                reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData);
+                reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData,
+                        reconciledPackages);
             }
         }
     }
 
     @GuardedBy("mInstallLock")
     private void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
-            boolean migrateAppData) {
-        reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
+            boolean migrateAppData, @Nullable ArraySet<String> reconciledPackages) {
+        reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */,
+                reconciledPackages);
     }
 
     /**
@@ -21616,7 +20204,8 @@
      */
     @GuardedBy("mInstallLock")
     private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
-            boolean migrateAppData, boolean onlyCoreApps) {
+            boolean migrateAppData, boolean onlyCoreApps,
+            @Nullable ArraySet<String> reconciledPackages) {
         Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
                 + Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
         List<String> result = onlyCoreApps ? new ArrayList<>() : null;
@@ -21679,6 +20268,9 @@
         int preparedCount = 0;
         for (PackageSetting ps : packages) {
             final String packageName = ps.name;
+            if (reconciledPackages != null && reconciledPackages.contains(packageName)) {
+                continue;
+            }
             if (ps.pkg == null) {
                 Slog.w(TAG, "Odd, missing scanned package " + packageName);
                 // TODO: might be due to legacy ASEC apps; we should circle back
@@ -21694,6 +20286,10 @@
             if (ps.getInstalled(userId)) {
                 prepareAppDataAndMigrate(batch, ps.pkg, userId, flags, migrateAppData);
                 preparedCount++;
+
+                if (reconciledPackages != null) {
+                    reconciledPackages.add(packageName);
+                }
             }
         }
         executeBatchLI(batch);
@@ -21727,7 +20323,7 @@
         StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class);
         for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
             final int flags;
-            if (StorageManager.isUserKeyUnlocked(user.id)) {
+            if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
             } else if (umInternal.isUserRunning(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE;
@@ -21735,13 +20331,17 @@
                 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(() -> {
                     // Note: this code block is executed with the Installer lock
                     // already held, since it's invoked as a side-effect of
                     // executeBatchLI()
-                    if (StorageManager.isUserKeyUnlocked(user.id)) {
+                    if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                         // Prepare app data on external storage; currently this is used to
                         // setup any OBB dirs that were created by the installer correctly.
                         int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid()));
@@ -21794,8 +20394,10 @@
         }
 
         final PackageSetting ps;
+        final String seInfoUser;
         synchronized (mLock) {
             ps = mSettings.getPackageLPr(pkg.getPackageName());
+            seInfoUser = SELinuxUtil.getSeinfoUser(ps.readUserState(userId));
         }
         final String volumeUuid = pkg.getVolumeUuid();
         final String packageName = pkg.getPackageName();
@@ -21806,7 +20408,7 @@
 
         Preconditions.checkNotNull(pkgSeInfo);
 
-        final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
+        final String seInfo = pkgSeInfo + seInfoUser;
         final int targetSdkVersion = pkg.getTargetSdkVersion();
 
         return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo,
@@ -22043,7 +20645,8 @@
             packageAbiOverride = ps.cpuAbiOverrideString;
             appId = UserHandle.getAppId(pkg.getUid());
             seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
-            label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState()));
+            label = String.valueOf(pm.getApplicationLabel(
+                    AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
             targetSdkVersion = pkg.getTargetSdkVersion();
             freezer = freezePackage(packageName, "movePackageInternal");
             installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
@@ -22209,8 +20812,9 @@
             return;
         }
 
-        final StorageManager storage = mInjector.getSystemService(StorageManager.class);
-        VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
+        final StorageManager storage = mInjector.getSystemService(StorageManager.class);;
+        VolumeInfo volume = storage.findVolumeByUuid(
+                StorageManager.convert(pkg.getVolumeUuid()).toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage());
 
         if (!isPreviousLocationExternal && pkg.isExternalStorage()) {
@@ -22399,7 +21003,7 @@
     }
 
     boolean readPermissionStateForUser(@UserIdInt int userId) {
-        synchronized (mPackages) {
+        synchronized (mLock) {
             mPermissionManager.writeLegacyPermissionStateTEMP();
             mSettings.readPermissionStateForUserSyncLPr(userId);
             mPermissionManager.readLegacyPermissionStateTEMP();
@@ -22471,7 +21075,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()),
@@ -22518,7 +21122,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()),
@@ -22576,137 +21180,6 @@
         }
     }
 
-    Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
-            long requiredInstalledVersionCode, int installFlags) {
-        if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
-            return verifyReplacingVersionCodeForApex(
-                    pkgLite, requiredInstalledVersionCode, installFlags);
-        }
-
-        String packageName = pkgLite.packageName;
-        synchronized (mLock) {
-            // Package which currently owns the data that the new package will own if installed.
-            // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
-            // will be null whereas dataOwnerPkg will contain information about the package
-            // which was uninstalled while keeping its data.
-            AndroidPackage dataOwnerPkg = mPackages.get(packageName);
-            if (dataOwnerPkg  == null) {
-                PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps != null) {
-                    dataOwnerPkg = ps.pkg;
-                }
-            }
-
-            if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
-                if (dataOwnerPkg == null) {
-                    String errorMsg = "Required installed version code was "
-                            + requiredInstalledVersionCode
-                            + " but package is not installed";
-                    Slog.w(TAG, errorMsg);
-                    return Pair.create(
-                            PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
-                }
-
-                if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
-                    String errorMsg = "Required installed version code was "
-                            + requiredInstalledVersionCode
-                            + " but actual installed version is "
-                            + dataOwnerPkg.getLongVersionCode();
-                    Slog.w(TAG, errorMsg);
-                    return Pair.create(
-                            PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
-                }
-            }
-
-            if (dataOwnerPkg != null) {
-                if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
-                        dataOwnerPkg.isDebuggable())) {
-                    try {
-                        checkDowngrade(dataOwnerPkg, pkgLite);
-                    } catch (PackageManagerException e) {
-                        String errorMsg = "Downgrade detected: " + e.getMessage();
-                        Slog.w(TAG, errorMsg);
-                        return Pair.create(
-                                PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
-                    }
-                }
-            }
-        }
-        return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
-    }
-
-    private Pair<Integer, String> verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
-            long requiredInstalledVersionCode, int installFlags) {
-        String packageName = pkgLite.packageName;
-
-        final PackageInfo activePackage = mApexManager.getPackageInfo(packageName,
-                ApexManager.MATCH_ACTIVE_PACKAGE);
-        if (activePackage == null) {
-            String errorMsg = "Attempting to install new APEX package " + packageName;
-            Slog.w(TAG, errorMsg);
-            return Pair.create(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, errorMsg);
-        }
-
-        final long activeVersion = activePackage.getLongVersionCode();
-        if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
-                && activeVersion != requiredInstalledVersionCode) {
-            String errorMsg = "Installed version of APEX package " + packageName
-                    + " does not match required. Active version: " + activeVersion
-                    + " required: " + requiredInstalledVersionCode;
-            Slog.w(TAG, errorMsg);
-            return Pair.create(PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
-        }
-
-        final boolean isAppDebuggable = (activePackage.applicationInfo.flags
-                & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-        final long newVersionCode = pkgLite.getLongVersionCode();
-        if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
-                && newVersionCode < activeVersion) {
-            String errorMsg = "Downgrade of APEX package " + packageName
-                    + " is not allowed. Active version: " + activeVersion
-                    + " attempted: " + newVersionCode;
-            Slog.w(TAG, errorMsg);
-            return Pair.create(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
-        }
-
-        return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
-    }
-
-    /**
-     * Check and throw if the given before/after packages would be considered a
-     * downgrade.
-     */
-    private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
-            throws PackageManagerException {
-        if (after.getLongVersionCode() < before.getLongVersionCode()) {
-            throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
-                    "Update version code " + after.versionCode + " is older than current "
-                            + 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());
-            }
-
-            if (!ArrayUtils.isEmpty(after.splitNames)) {
-                for (int i = 0; i < after.splitNames.length; i++) {
-                    final String splitName = after.splitNames[i];
-                    final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
-                    if (j != -1) {
-                        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]);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     private static class MoveCallbacks extends Handler {
         private static final int MSG_CREATED = 1;
         private static final int MSG_STATUS_CHANGED = 2;
@@ -22954,6 +21427,29 @@
         public boolean hasSystemFeature(String featureName, int version) {
             return PackageManagerService.this.hasSystemFeature(featureName, version);
         }
+
+        @Override
+        public void registerStagedApexObserver(IStagedApexObserver observer) {
+            mInstallerService.getStagingManager().registerStagedApexObserver(observer);
+        }
+
+        @Override
+        public void unregisterStagedApexObserver(IStagedApexObserver observer) {
+            mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
+        }
+
+        @Override
+        public String[] getStagedApexModuleNames() {
+            return mInstallerService.getStagingManager()
+                    .getStagedApexModuleNames().toArray(new String[0]);
+        }
+
+        @Override
+        @Nullable
+        public StagedApexInfo getStagedApexInfo(String moduleName) {
+            return mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
+        }
+
     }
 
     private AndroidPackage getPackage(String packageName) {
@@ -23093,6 +21589,12 @@
             return PackageManagerService.this.getPackage(packageName);
         }
 
+        @Nullable
+        @Override
+        public AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
+            return PackageManagerService.this.getPackage(packageName);
+        }
+
         @Override
         public AndroidPackage getPackage(int uid) {
             return PackageManagerService.this.getPackage(uid);
@@ -23104,6 +21606,12 @@
             return PackageManagerService.this.getPackageSetting(packageName);
         }
 
+        @Nullable
+        @Override
+        public PackageState getPackageState(@NonNull String packageName) {
+            return PackageManagerService.this.getPackageState(packageName);
+        }
+
         @Override
         public PackageList getPackageList(PackageListObserver observer) {
             synchronized (mLock) {
@@ -23401,6 +21909,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());
@@ -23516,6 +22031,13 @@
         @Override
         public void grantImplicitAccess(int userId, Intent intent,
                 int recipientAppId, int visibleUid, boolean direct) {
+            grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
+                    false /* retainOnUpdate */);
+        }
+
+        @Override
+        public void grantImplicitAccess(int userId, Intent intent,
+                int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
             synchronized (mLock) {
                 final AndroidPackage visiblePackage = getPackage(visibleUid);
                 final int recipientUid = UserHandle.getUid(userId, recipientAppId);
@@ -23536,7 +22058,8 @@
                     accessGranted = mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
                             recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
                 } else {
-                    accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid);
+                    accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
+                            retainOnUpdate);
                 }
                 if (accessGranted) {
                     ApplicationPackageManager.invalidateGetPackagesForUidCache();
@@ -23801,11 +22324,12 @@
 
         @Override
         public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
-            synchronized (mLock) {
-                for (int index = 0; index < mSettings.getPackagesLocked().size(); index++) {
-                    actionLocked.accept(mSettings.getPackagesLocked().valueAt(index));
-                }
-            }
+            PackageManagerService.this.forEachPackageSetting(actionLocked);
+        }
+
+        @Override
+        public void forEachPackageState(boolean locked, Consumer<PackageState> action) {
+            PackageManagerService.this.forEachPackageState(locked, action);
         }
 
         @Override
@@ -24280,10 +22804,15 @@
         return mComputer.getPackageSetting(packageName);
     }
 
-    private PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
+    PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
         return mComputer.getPackageSettingInternal(packageName, callingUid);
     }
 
+    @Nullable
+    private PackageState getPackageState(String packageName) {
+        return mComputer.getPackageState(packageName);
+    }
+
     void forEachPackage(Consumer<AndroidPackage> actionLocked) {
         synchronized (mLock) {
             int numPackages = mPackages.size();
@@ -24293,6 +22822,29 @@
         }
     }
 
+    private void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+        synchronized (mLock) {
+            int size = mSettings.getPackagesLocked().size();
+            for (int index = 0; index < size; index++) {
+                actionLocked.accept(mSettings.getPackagesLocked().valueAt(index));
+            }
+        }
+    }
+
+    private void forEachPackageState(boolean locked, Consumer<PackageState> action) {
+        if (locked) {
+            forEachPackageSetting(action::accept);
+        } else {
+            List<PackageState> packageStates = new ArrayList<>();
+            forEachPackageSetting(pkgSetting ->
+                    packageStates.add(PackageStateImpl.copy(pkgSetting)));
+            int size = packageStates.size();
+            for (int index = 0; index < size; index++) {
+                action.accept(packageStates.get(index));
+            }
+        }
+    }
+
     void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
             @UserIdInt int userId) {
         synchronized (mLock) {
@@ -24476,7 +23028,7 @@
         }
         int visibleUid = providerInfo.applicationInfo.uid;
         mPmInternal.grantImplicitAccess(userId, null /*Intent*/, UserHandle.getAppId(recipientUid),
-                visibleUid, false);
+                visibleUid, false /*direct*/);
     }
 
     boolean canHaveOatDir(String packageName) {
@@ -24922,5 +23474,3 @@
         }
     }
 }
-
-
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 4862021..e4f6398 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -581,8 +581,12 @@
                             apkLiteResult.getException());
                 }
                 final ApkLite apkLite = apkLiteResult.getResult();
-                final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite, null,
-                        null, null, null, null, null, apkLite.getTargetSdkVersion());
+                final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite,
+                        null /* splitNames */, null /* isFeatureSplits */,
+                        null /* usesSplitNames */, null /* configForSplit */,
+                        null /* splitApkPaths */, null /* splitRevisionCodes */,
+                        apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */,
+                        null /* splitTypes */);
                 sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
                         params.sessionParams.abiOverride, fd.getFileDescriptor());
             } catch (IOException e) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 3763262..249423e 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -20,7 +20,10 @@
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.pkg.PackageUserState;
 import android.service.pm.PackageProto;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -30,6 +33,7 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.pm.pkg.AndroidPackageApi;
 import com.android.server.pm.pkg.PackageStateUnserialized;
 import com.android.server.utils.SnapshotCache;
 
@@ -189,7 +193,14 @@
         return pkg;
     }
 
-    public int getSharedUserId() {
+    public Integer getSharedUserId() {
+        if (sharedUser != null) {
+            return sharedUser.userId;
+        }
+        return null;
+    }
+
+    public int getSharedUserIdInt() {
         if (sharedUser != null) {
             return sharedUser.userId;
         }
@@ -446,4 +457,8 @@
         mDomainSetId = domainSetId;
         return this;
     }
+
+    public String getPackageName() {
+        return name;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 717f3d5..62c8477 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -42,6 +42,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
 
 import java.io.File;
 import java.util.Arrays;
@@ -53,7 +54,7 @@
 /**
  * Settings base class for pending and resolved classes.
  */
-public abstract class PackageSettingBase extends SettingBase {
+public abstract class PackageSettingBase extends SettingBase implements PackageState {
 
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
@@ -297,7 +298,7 @@
         if (state == null) {
             return DEFAULT_USER_STATE;
         }
-        state.categoryHint = categoryHint;
+//        state.categoryHint = categoryHint;
         return state;
     }
 
@@ -455,7 +456,7 @@
         return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
     }
 
-    void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
+    boolean addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
             PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
         final PackageUserState existingUserState = modifyUserState(userId);
         final PackageUserState.SuspendParams newSuspendParams =
@@ -464,21 +465,27 @@
         if (existingUserState.suspendParams == null) {
             existingUserState.suspendParams = new ArrayMap<>();
         }
-        existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
+        final PackageUserState.SuspendParams oldSuspendParams =
+                existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
         existingUserState.suspended = true;
         onChanged();
+        return !Objects.equals(oldSuspendParams, newSuspendParams);
     }
 
-    void removeSuspension(String suspendingPackage, int userId) {
+    boolean removeSuspension(String suspendingPackage, int userId) {
+        boolean wasModified = false;
         final PackageUserState existingUserState = modifyUserState(userId);
         if (existingUserState.suspendParams != null) {
-            existingUserState.suspendParams.remove(suspendingPackage);
+            if (existingUserState.suspendParams.remove(suspendingPackage) != null) {
+                wasModified = true;
+            }
             if (existingUserState.suspendParams.size() == 0) {
                 existingUserState.suspendParams = null;
             }
         }
         existingUserState.suspended = (existingUserState.suspendParams != null);
         onChanged();
+        return wasModified;
     }
 
     void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
@@ -740,7 +747,7 @@
     }
 
     /** @see #mPath */
-    File getPath() {
+    public File getPath() {
         return mPath;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
index a1e5051..76364fe 100644
--- a/services/core/java/com/android/server/pm/PackageSignatures.java
+++ b/services/core/java/com/android/server/pm/PackageSignatures.java
@@ -174,7 +174,16 @@
                                 if (index >= 0 && index < readSignatures.size()) {
                                     Signature sig = readSignatures.get(index);
                                     if (sig != null) {
-                                        signatures.add(sig);
+                                        // An app using a shared signature in its signing lineage
+                                        // can have unique capabilities assigned to this previous
+                                        // signer; create a new instance of this Signature to ensure
+                                        // its flags do not overwrite those of the instance from
+                                        // readSignatures.
+                                        if (isPastSigs) {
+                                            signatures.add(new Signature(sig));
+                                        } else {
+                                            signatures.add(sig);
+                                        }
                                         signatureParsed = true;
                                     } else {
                                         PackageManagerService.reportSettingsProblem(Log.WARN,
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index a7e1a62..9f3d190 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -28,6 +28,7 @@
 
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 
 import libcore.io.IoUtils;
 
@@ -363,7 +364,7 @@
         if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) {
             return sharedUserSetting.seInfoTargetSdkVersion;
         }
-        final ApplicationInfo appInfo = pkg.toAppInfoWithoutState();
+        final ApplicationInfo appInfo = AndroidPackageUtils.generateAppInfoWithoutState(pkg);
         if (compatibility.isChangeEnabledInternal(SELINUX_LATEST_CHANGES, appInfo)) {
             return Math.max(
                     android.os.Build.VERSION_CODES.CUR_DEVELOPMENT, pkg.getTargetSdkVersion());
diff --git a/services/core/java/com/android/server/pm/ScanPartition.java b/services/core/java/com/android/server/pm/ScanPartition.java
new file mode 100644
index 0000000..e1d2b3b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ScanPartition.java
@@ -0,0 +1,80 @@
+/*
+ * 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.SCAN_AS_ODM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR;
+
+import android.annotation.NonNull;
+import android.content.pm.PackagePartitions;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+
+/**
+ * List of partitions to be scanned during system boot
+ */
+@VisibleForTesting
+public class ScanPartition extends PackagePartitions.SystemPartition {
+    @PackageManagerService.ScanFlags
+    public final int scanFlag;
+
+    public ScanPartition(@NonNull PackagePartitions.SystemPartition partition) {
+        super(partition);
+        scanFlag = scanFlagForPartition(partition);
+    }
+
+    /**
+     * Creates a partition containing the same folders as the original partition but with a
+     * different root folder. The new partition will include the scan flags of the original
+     * partition along with any specified additional scan flags.
+     */
+    public ScanPartition(@NonNull File folder, @NonNull ScanPartition original,
+            @PackageManagerService.ScanFlags int additionalScanFlag) {
+        super(folder, original);
+        this.scanFlag = original.scanFlag | additionalScanFlag;
+    }
+
+    private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
+        switch (partition.type) {
+            case PackagePartitions.PARTITION_SYSTEM:
+                return 0;
+            case PackagePartitions.PARTITION_VENDOR:
+                return SCAN_AS_VENDOR;
+            case PackagePartitions.PARTITION_ODM:
+                return SCAN_AS_ODM;
+            case PackagePartitions.PARTITION_OEM:
+                return SCAN_AS_OEM;
+            case PackagePartitions.PARTITION_PRODUCT:
+                return SCAN_AS_PRODUCT;
+            case PackagePartitions.PARTITION_SYSTEM_EXT:
+                return SCAN_AS_SYSTEM_EXT;
+            default:
+                throw new IllegalStateException("Unable to determine scan flag for "
+                        + partition.getFolder());
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getFolder().getAbsolutePath() + ":" + scanFlag;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java
index 6915a50..34f86ba 100644
--- a/services/core/java/com/android/server/pm/ScanResult.java
+++ b/services/core/java/com/android/server/pm/ScanResult.java
@@ -36,6 +36,11 @@
      */
     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.
      */
@@ -52,6 +57,7 @@
             ScanRequest request, boolean success,
             @Nullable PackageSetting pkgSetting,
             @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
+            boolean needsNewAppId,
             SharedLibraryInfo staticSharedLibraryInfo,
             List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
         mRequest = request;
@@ -59,6 +65,7 @@
         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..95e2d0a 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;
@@ -1161,7 +1161,7 @@
         }
         for (UserInfo user : allUsers) {
             final PackageUserState oldUserState = oldPackage == null
-                    ? PackageSettingBase.DEFAULT_USER_STATE
+                    ? PackageSetting.DEFAULT_USER_STATE
                     : oldPackage.readUserState(user.id);
             if (!oldUserState.equals(newPackage.readUserState(user.id))) {
                 writePackageRestrictionsLPr(user.id);
@@ -2733,9 +2733,6 @@
         } else {
             serializer.attributeInt(null, "sharedUserId", pkg.appId);
         }
-        if (pkg.uidError) {
-            serializer.attributeBoolean(null, "uidError", true);
-        }
         InstallSource installSource = pkg.installSource;
         if (installSource.installerPackageName != null) {
             serializer.attribute(null, "installer", installSource.installerPackageName);
@@ -3004,7 +3001,7 @@
 
         for (int i = 0; i < N; i++) {
             final PackageSetting p = mPendingPackages.get(i);
-            final int sharedUserId = p.getSharedUserId();
+            final int sharedUserId = p.getSharedUserIdInt();
             final Object idObj = getSettingLPr(sharedUserId);
             if (idObj instanceof SharedUserSetting) {
                 final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
@@ -3089,8 +3086,7 @@
         // Read preferred apps from .../etc/preferred-apps directories.
         int size = PackageManagerService.SYSTEM_PARTITIONS.size();
         for (int index = 0; index < size; index++) {
-            PackageManagerService.ScanPartition partition =
-                    PackageManagerService.SYSTEM_PARTITIONS.get(index);
+            ScanPartition partition = PackageManagerService.SYSTEM_PARTITIONS.get(index);
 
             File preferredDir = new File(partition.getFolder(), "etc/preferred-apps");
             if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -3288,7 +3284,7 @@
             IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
         final List<ResolveInfo> ri =
                 pmInternal.queryIntentActivities(
-                        intent, intent.getType(), flags, Binder.getCallingUid(), 0);
+                        intent, intent.getType(), flags, Binder.getCallingUid(), userId);
         if (PackageManagerService.DEBUG_PREFERRED) {
             Log.d(TAG, "Queried " + intent + " results: " + ri);
         }
@@ -3523,7 +3519,6 @@
         String volumeUuid = null;
         boolean updateAvailable = false;
         int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
-        boolean uidError = false;
         int pkgFlags = 0;
         int pkgPrivateFlags = 0;
         long timeStamp = 0;
@@ -3539,7 +3534,6 @@
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
             userId = parser.getAttributeInt(null, "userId", 0);
-            uidError = parser.getAttributeBoolean(null, "uidError", false);
             sharedUserId = parser.getAttributeInt(null, "sharedUserId", 0);
             codePathStr = parser.getAttributeValue(null, "codePath");
 
@@ -3696,7 +3690,6 @@
                             + userId + " at " + parser.getPositionDescription());
         }
         if (packageSetting != null) {
-            packageSetting.uidError = uidError;
             InstallSource installSource = InstallSource.create(
                     installInitiatingPackageName, installOriginatingPackageName,
                     installerPackageName, installerAttributionTag, isOrphaned,
@@ -3878,8 +3871,8 @@
         }
     }
 
-    private void readDisabledComponentsLPw(PackageSettingBase packageSetting,
-            TypedXmlPullParser parser, int userId) throws IOException, XmlPullParserException {
+    private void readDisabledComponentsLPw(PackageSetting packageSetting, TypedXmlPullParser parser,
+            int userId) throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -3906,8 +3899,8 @@
         }
     }
 
-    private void readEnabledComponentsLPw(PackageSettingBase packageSetting,
-            TypedXmlPullParser parser, int userId) throws IOException, XmlPullParserException {
+    private void readEnabledComponentsLPw(PackageSetting packageSetting, TypedXmlPullParser parser,
+            int userId) throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4513,8 +4506,6 @@
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
             final int apkSigningVersion = pkg.getSigningDetails().getSignatureSchemeVersion();
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
-            pw.print(prefix); pw.print("  applicationInfo=");
-            pw.println(pkg.toAppInfoToString());
             pw.print(prefix); pw.print("  flags=");
             printFlags(pw, PackageInfoUtils.appInfoFlags(pkg, ps), FLAG_DUMP_SPEC); pw.println();
             int privateFlags = PackageInfoUtils.appInfoPrivateFlags(pkg, ps);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 945df5d..0951e0d 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1674,6 +1674,19 @@
         mContext.enforceCallingPermission(permission, message);
     }
 
+    private void verifyCallerUserId(@UserIdInt int userId) {
+        if (isCallerSystem()) {
+            return; // no check
+        }
+
+        final int callingUid = injectBinderCallingUid();
+
+        // Otherwise, make sure the arguments are valid.
+        if (UserHandle.getUserId(callingUid) != userId) {
+            throw new SecurityException("Invalid user-ID");
+        }
+    }
+
     private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
         Preconditions.checkStringNotEmpty(packageName, "packageName");
 
@@ -2857,6 +2870,8 @@
 
     @Override
     public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
+        verifyCallerUserId(callingUserId);
+
         final long token = injectClearCallingIdentity();
         try {
             return mShortcutRequestPinProcessor
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9dcae3d..4dfb6b8 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
@@ -28,6 +29,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.ApexStagedEvent;
+import android.content.pm.IStagedApexObserver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
@@ -36,6 +39,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.SigningDetails;
 import android.content.pm.SigningDetails.SignatureSchemeVersion;
+import android.content.pm.StagedApexInfo;
 import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
@@ -52,6 +56,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.Slog;
@@ -80,7 +85,9 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -99,7 +106,8 @@
     private final ApexManager mApexManager;
     private final PowerManager mPowerManager;
     private final Context mContext;
-    private final PreRebootVerificationHandler mPreRebootVerificationHandler;
+    @VisibleForTesting
+    final PreRebootVerificationHandler mPreRebootVerificationHandler;
     private final Supplier<PackageParser2> mPackageParserSupplier;
 
     private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
@@ -115,6 +123,9 @@
     @GuardedBy("mSuccessfulStagedSessionIds")
     private final List<Integer> mSuccessfulStagedSessionIds = new ArrayList<>();
 
+    @GuardedBy("mStagedApexObservers")
+    private final List<IStagedApexObserver> mStagedApexObservers = new ArrayList<>();
+
     private final CompletableFuture<Void> mBootCompleted = new CompletableFuture<>();
 
     interface StagedSession {
@@ -204,6 +215,35 @@
         mApexManager.markBootCompleted();
     }
 
+    void registerStagedApexObserver(IStagedApexObserver observer) {
+        if (observer == null) {
+            return;
+        }
+        if  (observer.asBinder() != null) {
+            try {
+                observer.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        synchronized (mStagedApexObservers) {
+                            mStagedApexObservers.remove(observer);
+                        }
+                    }
+                }, 0);
+            } catch (RemoteException re) {
+                Slog.w(TAG, re.getMessage());
+            }
+        }
+        synchronized (mStagedApexObservers) {
+            mStagedApexObservers.add(observer);
+        }
+    }
+
+    void unregisterStagedApexObserver(IStagedApexObserver observer) {
+        synchronized (mStagedApexObservers) {
+            mStagedApexObservers.remove(observer);
+        }
+    }
+
     /**
      * Validates the signature used to sign the container of the new apex package
      *
@@ -808,6 +848,9 @@
                 // Also, cleaning up the stageDir prevents the apex from being activated.
                 Slog.e(TAG, "Failed to abort apex session " + session.sessionId());
             }
+            if (session.containsApexSession()) {
+                notifyStagedApexObservers();
+            }
         }
 
         // Session was successfully aborted from apexd (if required) and pre-reboot verification
@@ -1093,7 +1136,107 @@
         return session;
     }
 
-    private final class PreRebootVerificationHandler extends Handler {
+    /**
+     * Returns ApexInfo about APEX contained inside the session as a {@code Map<String, ApexInfo>},
+     * where the key of the map is the module name of the ApexInfo.
+     *
+     * Returns an empty map if there is any error.
+     */
+    @VisibleForTesting
+    @NonNull
+    Map<String, ApexInfo> getStagedApexInfos(@NonNull StagedSession session) {
+        Preconditions.checkArgument(session != null, "Session is null");
+        Preconditions.checkArgument(!session.hasParentSessionId(),
+                session.sessionId() + " session has parent session");
+        Preconditions.checkArgument(session.containsApexSession(),
+                session.sessionId() + " session does not contain apex");
+
+        // Even if caller calls this method on ready session, the session could be abandoned
+        // right after this method is called.
+        if (!session.isSessionReady() || session.isDestroyed()) {
+            return Collections.emptyMap();
+        }
+
+        ApexSessionParams params = new ApexSessionParams();
+        params.sessionId = session.sessionId();
+        final IntArray childSessionIds = new IntArray();
+        if (session.isMultiPackage()) {
+            for (StagedSession s : session.getChildSessions()) {
+                if (s.isApexSession()) {
+                    childSessionIds.add(s.sessionId());
+                }
+            }
+        }
+        params.childSessionIds = childSessionIds.toArray();
+
+        ApexInfo[] infos = mApexManager.getStagedApexInfos(params);
+        Map<String, ApexInfo> result = new ArrayMap<>();
+        for (ApexInfo info : infos) {
+            result.put(info.moduleName, info);
+        }
+        return result;
+    }
+
+    /**
+     * Returns apex module names of all packages that are staged ready
+     */
+    List<String> getStagedApexModuleNames() {
+        List<String> result = new ArrayList<>();
+        synchronized (mStagedSessions) {
+            for (int i = 0; i < mStagedSessions.size(); i++) {
+                final StagedSession session = mStagedSessions.valueAt(i);
+                if (!session.isSessionReady() || session.isDestroyed()
+                        || session.hasParentSessionId() || !session.containsApexSession()) {
+                    continue;
+                }
+                result.addAll(getStagedApexInfos(session).keySet());
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns ApexInfo of the {@code moduleInfo} provided if it is staged, otherwise returns null.
+     */
+    @Nullable
+    StagedApexInfo getStagedApexInfo(String moduleName) {
+        synchronized (mStagedSessions) {
+            for (int i = 0; i < mStagedSessions.size(); i++) {
+                final StagedSession session = mStagedSessions.valueAt(i);
+                if (!session.isSessionReady() || session.isDestroyed()
+                        || session.hasParentSessionId() || !session.containsApexSession()) {
+                    continue;
+                }
+                ApexInfo ai = getStagedApexInfos(session).get(moduleName);
+                if (ai != null) {
+                    StagedApexInfo info = new StagedApexInfo();
+                    info.moduleName = ai.moduleName;
+                    info.diskImagePath = ai.modulePath;
+                    info.versionCode = ai.versionCode;
+                    info.versionName = ai.versionName;
+                    return info;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void notifyStagedApexObservers() {
+        synchronized (mStagedApexObservers) {
+            for (IStagedApexObserver observer : mStagedApexObservers) {
+                ApexStagedEvent event = new ApexStagedEvent();
+                event.stagedApexModuleNames = getStagedApexModuleNames().toArray(new String[0]);
+                try {
+                    observer.onApexStaged(event);
+                } catch (RemoteException re) {
+                    Slog.w(TAG, "Failed to contact the observer " + re.getMessage());
+                }
+            }
+        }
+    }
+
+    @VisibleForTesting
+    final class PreRebootVerificationHandler extends Handler {
 
         PreRebootVerificationHandler(Looper looper) {
             super(looper);
@@ -1114,7 +1257,8 @@
          */
         private static final int MSG_PRE_REBOOT_VERIFICATION_START = 1;
         private static final int MSG_PRE_REBOOT_VERIFICATION_APEX = 2;
-        private static final int MSG_PRE_REBOOT_VERIFICATION_END = 3;
+        @VisibleForTesting
+        static final int MSG_PRE_REBOOT_VERIFICATION_END = 3;
 
         @Override
         public void handleMessage(Message msg) {
@@ -1314,6 +1458,7 @@
                 if (hasApex) {
                     try {
                         mApexManager.markStagedSessionReady(session.sessionId());
+                        notifyStagedApexObservers();
                     } catch (PackageManagerException e) {
                         session.setSessionFailed(e.error, e.getMessage());
                         return;
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index cc5187e..95c9191 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -104,20 +104,6 @@
       "file_patterns": ["(/|^)ShortcutService\\.java"]
     },
     {
-      "name": "CtsContentTestCases",
-      "options": [
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-          "include-filter": "android.content.pm.cts"
-        }
-      ]
-    },
-    {
       "name": "GtsContentTestCases",
       "options": [
         {
@@ -183,6 +169,22 @@
       ]
     }
   ],
+  "presubmit-large": [
+    {
+      "name": "CtsContentTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.content.pm.cts"
+        }
+      ]
+    }
+  ],
   "postsubmit": [
     {
       "name": "CtsPermissionTestCases",
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e8182e0..40e0526 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4805,7 +4805,7 @@
         mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
         t.traceEnd();
         t.traceBegin("reconcileAppsData");
-        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData);
+        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData, null);
         t.traceEnd();
 
         if (userId != UserHandle.USER_SYSTEM) {
@@ -4821,11 +4821,14 @@
     /**
      * Called right before a user is unlocked. This gives us a chance to prepare
      * app storage.
+     *
+     * @return set of packages that reconciled app data
      */
-    public void onBeforeUnlockUser(@UserIdInt int userId) {
+    @NonNull public ArraySet<String> onBeforeUnlockUser(@UserIdInt int userId) {
         UserInfo userInfo = getUserInfo(userId);
         if (userInfo == null) {
-            return;
+            // PMS requires mutable set, so the API uses ArraySet to prevent Collections.emptySet()
+            return new ArraySet<>();
         }
         final int userSerial = userInfo.serialNumber;
         // Migrate only if build fingerprints mismatch
@@ -4836,8 +4839,33 @@
         mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
         t.traceEnd();
 
-        t.traceBegin("reconcileAppsData-" + userId);
-        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData);
+        final ArraySet<String> reconciledPackages = new ArraySet<>();
+        t.traceBegin("reconcileAppsDataFirstPass-" + userId);
+        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData,
+                reconciledPackages);
+        t.traceEnd();
+        return reconciledPackages;
+    }
+
+    /**
+     * Called right after a user state is moved to {@link UserState#STATE_RUNNING_UNLOCKING}. This
+     * gives us a chance to reconcile app data for apps installed since
+     * {@link #onBeforeUnlockUser(int)} was called.
+     *
+     * @param previouslyReconciledPackages the result from {@link #onBeforeUnlockUser(int)}
+     */
+    public void onUserStateRunningUnlocking(@UserIdInt int userId,
+            @NonNull ArraySet<String> previouslyReconciledPackages) {
+        final UserInfo userInfo = getUserInfo(userId);
+        if (userInfo == null) {
+            return;
+        }
+        // Migrate only if build fingerprints mismatch
+        boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint);
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("reconcileAppsDataSecondPass-" + userId);
+        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData,
+                previouslyReconciledPackages);
         t.traceEnd();
     }
 
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index 3c499de..dae4038 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -131,13 +131,12 @@
     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);
+        super(user, pm);
         mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
         mObserver = observer;
         mInstallFlags = sessionParams.installFlags;
@@ -155,7 +154,6 @@
                 ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
         mSessionId = sessionId;
         mPackageLite = lite;
-        mPm = pm;
     }
 
     @Override
@@ -168,7 +166,7 @@
         PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
                 mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
 
-        Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+        Pair<Integer, String> ret = verifyReplacingVersionCode(
                 pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
         setReturnCode(ret.first, ret.second);
         if (mRet != INSTALL_SUCCEEDED) {
@@ -707,7 +705,7 @@
     public void verifyStage(List<VerificationParams> children)
             throws PackageManagerException {
         final MultiPackageVerificationParams params =
-                new MultiPackageVerificationParams(this, children);
+                new MultiPackageVerificationParams(this, children, mPm);
         mPm.mHandler.post(params::startCopy);
     }
 
@@ -720,9 +718,9 @@
         private final List<VerificationParams> mChildParams;
         private final Map<VerificationParams, Integer> mVerificationState;
 
-        MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children)
-                throws PackageManagerException {
-            super(parent.getUser());
+        MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children,
+                PackageManagerService pm) throws PackageManagerException {
+            super(parent.getUser(), pm);
             if (children.size() == 0) {
                 throw new PackageManagerException("No child sessions found!");
             }
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index 74ec161..59b7cbd 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -76,7 +76,8 @@
         p.unmarshall(bytes, 0, bytes.length);
         p.setDataPosition(0);
 
-        final PackageParserCacheHelper.ReadHelper helper = new PackageParserCacheHelper.ReadHelper(p);
+        final PackageParserCacheHelper.ReadHelper helper =
+                new PackageParserCacheHelper.ReadHelper(p);
         helper.startAndInstall();
 
         ParsedPackage pkg = new PackageImpl(p);
@@ -98,9 +99,10 @@
     @VisibleForTesting
     public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
         final Parcel p = Parcel.obtain();
-        final PackageParserCacheHelper.WriteHelper helper = new PackageParserCacheHelper.WriteHelper(p);
+        final PackageParserCacheHelper.WriteHelper helper =
+                new PackageParserCacheHelper.WriteHelper(p);
 
-        pkg.writeToParcel(p, 0 /* flags */);
+        ((PackageImpl) pkg).writeToParcel(p, 0 /* flags */);
 
         helper.finishAndUninstall();
 
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index fa9ed66..876c534 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -208,8 +208,8 @@
      */
     @Nullable
     public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
-            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId,
-            @Nullable PackageSetting pkgSetting) {
+            @PackageManager.ApplicationInfoFlags int flags, @NonNull PackageUserState state,
+            int userId, @Nullable PackageSetting pkgSetting) {
         if (pkg == null) {
             return null;
         }
@@ -233,6 +233,9 @@
             info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
                     ? null : usesLibraryFiles.toArray(new String[0]);
             info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+            if (info.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+                info.category = pkgSetting.getCategoryOverride();
+            }
         }
 
         info.seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
index 432394a..c67d0d2 100644
--- a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -29,6 +29,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 
 /**
@@ -63,7 +64,7 @@
                     ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
             try {
                 return platformCompat.isChangeEnabled(REMOVE_ANDROID_TEST_BASE,
-                        pkg.toAppInfoWithoutState());
+                        AndroidPackageUtils.generateAppInfoWithoutState(pkg));
             } catch (RemoteException | NullPointerException e) {
                 Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
             }
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 8a8a302..4334bf6 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -21,7 +21,7 @@
 import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
 import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackage;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -82,7 +82,7 @@
         boolean hasClass = false;
         String className = "android.content.pm.AndroidTestBaseUpdater";
         try {
-            Class clazz = (PackageParser.class.getClassLoader().loadClass(className));
+            Class clazz = ParsingPackage.class.getClassLoader().loadClass(className);
             hasClass = clazz != null;
             Log.i(TAG, "Loaded " + className);
         } catch (ClassNotFoundException e) {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl
deleted file mode 100644
index ab3cf7c..0000000
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-**
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.content.pm.parsing;
-
-/* @hide */
-parcelable AndroidPackage;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 0d2bcec..bf7d897 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -17,87 +17,22 @@
 package com.android.server.pm.parsing.pkg;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PermissionGroupInfo;
-import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ParsedAttribution;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.util.ArraySet;
-import android.util.Pair;
 
-import com.android.internal.R;
-
-import java.security.PublicKey;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
+import com.android.server.pm.pkg.AndroidPackageApi;
 
 /**
- * The last state of a package during parsing/install before it is available in
- * {@link com.android.server.pm.PackageManagerService#mPackages}.
- *
+ * The last state of a package during parsing/install before it is available in {@link
+ * com.android.server.pm.PackageManagerService#mPackages}.
+ * <p>
  * It is the responsibility of the caller to understand what data is available at what step of the
  * parsing or install process.
- *
- * TODO(b/135203078): Nullability annotations
- * TODO(b/135203078): Remove get/setAppInfo differences
+ * <p>
  *
  * @hide
  */
-public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPackageRead, Parcelable {
+public interface AndroidPackage extends ParsingPackageRead, AndroidPackageApi {
 
-    /**
-     * The names of packages to adopt ownership of permissions from, parsed under
-     * {@link ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
-     * @see R.styleable#AndroidManifestOriginalPackage_name
-     */
-    @NonNull
-    List<String> getAdoptPermissions();
-
-    /** Path of base APK */
-    @NonNull
-    String getBaseApkPath();
-
-    /** Revision code of base APK */
-    int getBaseRevisionCode();
-
-    /**
-     * The path to the folder containing the base APK and any installed splits.
-     */
-    @NonNull
-    String getPath();
-
-    /**
-     * Permissions requested but not in the manifest. These may have been split or migrated from
-     * previous versions/definitions.
-     */
-    @NonNull
-    List<String> getImplicitPermissions();
-
-    /**
-     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
-     * {@link ParsingPackageUtils#TAG_KEY_SETS}.
-     * @see R.styleable#AndroidManifestKeySet
-     * @see R.styleable#AndroidManifestPublicKey
-     */
-    @NonNull
-    Map<String, ArraySet<PublicKey>> getKeySetMapping();
-
-    /**
-     * Library names this package is declared as, for use by other packages with "uses-library".
-     * @see R.styleable#AndroidManifestLibrary
-     */
-    @NonNull
-    List<String> getLibraryNames();
 
     /**
      * The package name as declared in the manifest, since the package can be renamed. For example,
@@ -105,224 +40,4 @@
      */
     @NonNull
     String getManifestPackageName();
-
-    /**
-     * We store the application meta-data independently to avoid multiple unwanted references
-     * TODO(b/135203078): What does this comment mean?
-     * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?)
-     */
-    @Nullable
-    Bundle getMetaData();
-
-    /**
-     * For system use to migrate from an old package name to a new one, moving over data
-     * if available.
-     * @see R.styleable#AndroidManifestOriginalPackage}
-     */
-    @NonNull
-    List<String> getOriginalPackages();
-
-    /**
-     * Map of overlayable name to actor name.
-     */
-    @NonNull
-    Map<String, String> getOverlayables();
-
-    /**
-     * The name of the package as used to identify it in the system. This may be adjusted by the
-     * system from the value declared in the manifest, and may not correspond to a Java code
-     * package.
-     * @see ApplicationInfo#packageName
-     * @see PackageInfo#packageName
-     */
-    @NonNull
-    String getPackageName();
-
-    /**
-     * @see PermissionGroupInfo
-     */
-    @NonNull
-    List<ParsedPermissionGroup> getPermissionGroups();
-
-    @NonNull
-    List<ParsedAttribution> getAttributions();
-
-    /**
-     * Used to determine the default preferred handler of an {@link Intent}.
-     *
-     * Map of component className to intent info inside that component.
-     * TODO(b/135203078): Is this actually used/working?
-     */
-    @NonNull
-    List<Pair<String, ParsedIntentInfo>> getPreferredActivityFilters();
-
-    /**
-     * System protected broadcasts.
-     * @see R.styleable#AndroidManifestProtectedBroadcast
-     */
-    @NonNull
-    List<String> getProtectedBroadcasts();
-
-    /**
-     * Intents that this package may query or require and thus requires visibility into.
-     * @see R.styleable#AndroidManifestQueriesIntent
-     */
-    @NonNull
-    List<Intent> getQueriesIntents();
-
-    /**
-     * Other packages that this package may query or require and thus requires visibility into.
-     * @see R.styleable#AndroidManifestQueriesPackage
-     */
-    @NonNull
-    List<String> getQueriesPackages();
-
-    /**
-     * If a system app declares {@link #getOriginalPackages()}, and the app was previously installed
-     * under one of those original package names, the {@link #getPackageName()} system identifier
-     * will be changed to that previously installed name. This will then be non-null, set to the
-     * manifest package name, for tracking the package under its true name.
-     *
-     * TODO(b/135203078): Remove this in favor of checking originalPackages.isEmpty and
-     *  getManifestPackageName
-     */
-    @Nullable
-    String getRealPackage();
-
-    /**
-     * SHA-512 hash of the only APK that can be used to update a system package.
-     * @see R.styleable#AndroidManifestRestrictUpdate
-     */
-    @Nullable
-    byte[] getRestrictUpdateHash();
-
-    /**
-     * The signature data of all APKs in this package, which must be exactly the same across the
-     * base and splits.
-     */
-    SigningDetails getSigningDetails();
-
-    /**
-     * TODO(b/135203078): Move split stuff to an inner data class
-     * @see ApplicationInfo#splitNames
-     * @see PackageInfo#splitNames
-     */
-    @Nullable
-    String[] getSplitNames();
-
-    /** Flags of any split APKs; ordered by parsed splitName */
-    @Nullable
-    int[] getSplitFlags();
-
-    /** @see R.styleable#AndroidManifestStaticLibrary_name */
-    @Nullable
-    String getStaticSharedLibName();
-
-    /** @see R.styleable#AndroidManifestStaticLibrary_version */
-    long getStaticSharedLibVersion();
-
-    /**
-     * {@link android.os.storage.StorageManager#convert(String)} version of
-     * {@link #getVolumeUuid()}.
-     * TODO(b/135203078): All usages call toString() on this. Can the string be returned directly,
-     *  or does the parsing logic in StorageManager have to run?
-     */
-    UUID getStorageUuid();
-
-    /**
-     * For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in
-     * {@link ParsingPackageUtils#TAG_KEY_SETS}.
-     * @see R.styleable#AndroidManifestUpgradeKeySet
-     */
-    @NonNull
-    Set<String> getUpgradeKeySets();
-
-    /** @see R.styleable#AndroidManifestUsesLibrary */
-    @NonNull
-    List<String> getUsesLibraries();
-
-    /**
-     * Like {@link #getUsesLibraries()}, but marked optional by setting
-     * {@link R.styleable#AndroidManifestUsesLibrary_required} to false . Application is expected
-     * to handle absence manually.
-     * @see R.styleable#AndroidManifestUsesLibrary
-     */
-    @NonNull
-    List<String> getUsesOptionalLibraries();
-
-    /** @see R.styleabele#AndroidManifestUsesNativeLibrary */
-    @NonNull
-    List<String> getUsesNativeLibraries();
-
-    /**
-     * Like {@link #getUsesNativeLibraries()}, but marked optional by setting
-     * {@link R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is
-     * expected to handle absence manually.
-     * @see R.styleable#AndroidManifestUsesNativeLibrary
-     */
-    @NonNull
-    List<String> getUsesOptionalNativeLibraries();
-
-    /**
-     * TODO(b/135203078): Move static library stuff to an inner data class
-     * @see R.styleable#AndroidManifestUsesStaticLibrary
-     */
-    @NonNull
-    List<String> getUsesStaticLibraries();
-
-    /** @see R.styleable#AndroidManifestUsesStaticLibrary_certDigest */
-    @Nullable
-    String[][] getUsesStaticLibrariesCertDigests();
-
-    /** @see R.styleable#AndroidManifestUsesStaticLibrary_version */
-    @Nullable
-    long[] getUsesStaticLibrariesVersions();
-
-    /** @see R.styleable#AndroidManifestApplication_forceQueryable */
-    boolean isForceQueryable();
-
-    boolean isCrossProfile();
-
-    /**
-     * The install time abi override to choose 32bit abi's when multiple abi's
-     * are present. This is only meaningfull for multiarch applications.
-     */
-    boolean isUse32BitAbi();
-
-    /**
-     * Set if the any of components are visible to instant applications.
-     * @see R.styleable#AndroidManifestActivity_visibleToInstantApps
-     * @see R.styleable#AndroidManifestProvider_visibleToInstantApps
-     * @see R.styleable#AndroidManifestService_visibleToInstantApps
-     */
-    boolean isVisibleToInstantApps();
-
-    /**
-     * Generates an {@link ApplicationInfo} object with only the data available in this object.
-     *
-     * TODO(b/135203078): Actually add this
-     * This does not contain any system or user state data, and should be avoided. Prefer
-     * com.android.server.pm.parsing.PackageInfoUtils#generateApplicationInfo(
-     * AndroidPackage, int, PackageUserState, int, com.android.server.pm.PackageSetting)
-     *
-     * @deprecated Access AndroidPackage fields directly.
-     */
-    @Deprecated
-    @NonNull
-    ApplicationInfo toAppInfoWithoutState();
-
-    /**
-     * Same as toAppInfoWithoutState except it does not compute any flags.
-     */
-    @NonNull
-    ApplicationInfo toAppInfoWithoutStateWithoutFlags();
-
-    /**
-     * TODO(b/135203078): Remove usages?
-     * @return a mock of what the previous package.applicationInfo would've returned for logging
-     * @deprecated don't use this in any new code, just print package name directly
-     */
-    @Deprecated
-    @NonNull
-    String toAppInfoToString();
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java
new file mode 100644
index 0000000..944e4ad
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java
@@ -0,0 +1,69 @@
+/*
+ * 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.pm.parsing.pkg;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+/**
+ * Methods that normal consumers should not have access to. This usually means the field is stateful
+ * or deprecated and should be access through {@link AndroidPackageUtils} or a system manager
+ * class.
+ * <p>
+ * This is a separate interface, not implemented by the base {@link AndroidPackage} because Java
+ * doesn't support non-public interface methods. The class must be cast to this interface.
+ * <p>
+ * Because they exist in different packages, some methods are duplicated from
+ * android.content.pm.parsing.ParsingPackageHidden.
+ */
+interface AndroidPackageHidden {
+
+    /**
+     * @see ApplicationInfo#primaryCpuAbi
+     */
+    @Nullable
+    String getPrimaryCpuAbi();
+
+    /**
+     * @see ApplicationInfo#seInfo
+     * TODO: This field is deriveable and might not have to be cached here.
+     */
+    @Nullable
+    String getSeInfo();
+
+    /**
+     * @see ApplicationInfo#secondaryCpuAbi
+     */
+    @Nullable
+    String getSecondaryCpuAbi();
+
+    /**
+     * @see PackageInfo#versionCode
+     * @see ApplicationInfo#versionCode
+     */
+    @Deprecated
+    int getVersionCode();
+
+    /**
+     * @see PackageInfo#versionCodeMajor
+     */
+    int getVersionCodeMajor();
+
+    // TODO(b/135203078): Hide and enforce going through PackageInfoUtils
+    ApplicationInfo toAppInfoWithoutState();
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index d40aada..5a8e793 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.VersionedPackage;
@@ -128,7 +127,7 @@
             throws PackageManagerException {
         Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
         String packageName = pkg.getPackageName();
-        long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
+        long versionCode = pkg.getLongVersionCode();
         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
         for (String dexMetadata : apkToDexMetadataList) {
             final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
@@ -253,10 +252,6 @@
                 ? pkg.getRoundIconRes() : pkg.getIconRes();
     }
 
-    public static long getLongVersionCode(AndroidPackage pkg) {
-        return PackageInfo.composeLongVersionCode(pkg.getVersionCodeMajor(), pkg.getVersionCode());
-    }
-
     /**
      * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY}
      * flag and the provided package is not a system package. Otherwise returns {@code true}.
@@ -270,7 +265,7 @@
 
     public static String getPrimaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
         if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.primaryCpuAbiString)) {
-            return pkg.getPrimaryCpuAbi();
+            return getRawPrimaryCpuAbi(pkg);
         }
 
         return pkgSetting.primaryCpuAbiString;
@@ -279,7 +274,7 @@
     public static String getSecondaryCpuAbi(AndroidPackage pkg,
             @Nullable PackageSetting pkgSetting) {
         if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.secondaryCpuAbiString)) {
-            return pkg.getSecondaryCpuAbi();
+            return getRawSecondaryCpuAbi(pkg);
         }
 
         return pkgSetting.secondaryCpuAbiString;
@@ -288,23 +283,17 @@
     /**
      * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
      * Otherwise prefer {@link #getPrimaryCpuAbi(AndroidPackage, PackageSetting)}.
-     *
-     * TODO(b/135203078): Actually hide the method
-     * Placed in the utility to hide the method on the interface.
      */
     public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
-        return pkg.getPrimaryCpuAbi();
+        return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi();
     }
 
     /**
      * Returns the secondary ABI as parsed from the package. Used only during parsing and
      * derivation. Otherwise prefer {@link #getSecondaryCpuAbi(AndroidPackage, PackageSetting)}.
-     *
-     * TODO(b/135203078): Actually hide the method
-     * Placed in the utility to hide the method on the interface.
      */
     public static String getRawSecondaryCpuAbi(AndroidPackage pkg) {
-        return pkg.getSecondaryCpuAbi();
+        return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi();
     }
 
     public static String getSeInfo(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
@@ -314,6 +303,25 @@
                 return overrideSeInfo;
             }
         }
-        return pkg.getSeInfo();
+        return ((AndroidPackageHidden) pkg).getSeInfo();
+    }
+
+    @Deprecated
+    @NonNull
+    public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) {
+        return ((AndroidPackageHidden) pkg).toAppInfoWithoutState();
+    }
+
+    /**
+     * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was
+     * actually renamed.
+     */
+    @Nullable
+    public static String getRealPackageOrNull(AndroidPackage pkg) {
+        if (pkg.getOriginalPackages().isEmpty() || !pkg.isSystem()) {
+            return null;
+        }
+
+        return pkg.getManifestPackageName();
     }
 }
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..61f7daf 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
@@ -22,6 +22,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.SELinuxUtil;
 import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.ParsingPackageImpl;
@@ -32,7 +33,6 @@
 import android.os.Environment;
 import android.os.Parcel;
 import android.os.UserHandle;
-import android.os.storage.StorageManager;
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -42,7 +42,6 @@
 import com.android.server.pm.parsing.PackageInfoUtils;
 
 import java.io.File;
-import java.util.UUID;
 
 /**
  * Extensions to {@link ParsingPackageImpl} including fields/state contained in the system server
@@ -53,8 +52,10 @@
  *
  * @hide
  */
-public final class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage {
+public class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage,
+        AndroidPackageHidden {
 
+    @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);
@@ -112,9 +116,6 @@
     @Nullable
     @DataClass.ParcelWith(ForInternedString.class)
     protected String seInfo;
-    @Nullable
-    @DataClass.ParcelWith(ForInternedString.class)
-    protected String seInfoUser;
 
     /**
      * This is an appId, the uid if the userId is == USER_SYSTEM
@@ -264,12 +265,6 @@
     }
 
     @Override
-    public PackageImpl setRealPackage(@Nullable String realPackage) {
-        super.setRealPackage(realPackage);
-        return this;
-    }
-
-    @Override
     public PackageImpl setPersistent(boolean value) {
         super.setPersistent(value);
         return this;
@@ -423,12 +418,6 @@
     }
 
     @Override
-    public PackageImpl setSeInfoUser(@Nullable String seInfoUser) {
-        this.seInfoUser = TextUtils.safeIntern(seInfoUser);
-        return this;
-    }
-
-    @Override
     public PackageImpl setSplitCodePaths(@Nullable String[] splitCodePaths) {
         this.splitCodePaths = splitCodePaths;
         if (splitCodePaths != null) {
@@ -483,19 +472,6 @@
     }
 
     @Override
-    public UUID getStorageUuid() {
-        return StorageManager.convert(volumeUuid);
-    }
-
-    @Deprecated
-    @Override
-    public String toAppInfoToString() {
-        return "PackageImpl{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + getPackageName() + "}";
-    }
-
-    @Override
     public ParsedPackage setCoreApp(boolean coreApp) {
         return setBoolean(Booleans.CORE_APP, coreApp);
     }
@@ -525,7 +501,7 @@
         appInfo.secondaryCpuAbi = secondaryCpuAbi;
         appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
         appInfo.seInfo = seInfo;
-        appInfo.seInfoUser = seInfoUser;
+        appInfo.seInfoUser = SELinuxUtil.COMPLETE_STR;
         appInfo.uid = uid;
         return appInfo;
     }
@@ -546,7 +522,6 @@
         sForInternedString.parcel(this.secondaryCpuAbi, dest, flags);
         dest.writeString(this.secondaryNativeLibraryDir);
         dest.writeString(this.seInfo);
-        dest.writeString(this.seInfoUser);
         dest.writeInt(this.uid);
         dest.writeInt(this.mBooleans);
     }
@@ -561,13 +536,13 @@
         this.secondaryCpuAbi = sForInternedString.unparcel(in);
         this.secondaryNativeLibraryDir = in.readString();
         this.seInfo = in.readString();
-        this.seInfoUser = in.readString();
         this.uid = in.readInt();
         this.mBooleans = in.readInt();
 
         assignDerivedFields();
     }
 
+    @NonNull
     public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
         @Override
         public PackageImpl createFromParcel(Parcel source) {
@@ -631,12 +606,6 @@
         return seInfo;
     }
 
-    @Nullable
-    @Override
-    public String getSeInfoUser() {
-        return seInfoUser;
-    }
-
     @Override
     public boolean isCoreApp() {
         return getBoolean(Booleans.CORE_APP);
@@ -695,7 +664,7 @@
         return uid;
     }
 
-    @DataClass.Generated.Member
+    @Override
     public PackageImpl setStub(boolean value) {
         setBoolean(Booleans.STUB, value);
         return this;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 0051bab..bb08f09 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -16,7 +16,6 @@
 
 package com.android.server.pm.parsing.pkg;
 
-import android.annotation.Nullable;
 import android.content.pm.SigningDetails;
 
 /**
@@ -55,8 +54,6 @@
 
     ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi);
 
-    ParsedPackage setRealPackage(@Nullable String realPackage);
-
     ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi);
 
     ParsedPackage setSigningDetails(SigningDetails signingDetails);
@@ -101,8 +98,6 @@
 
     ParsedPackage setSeInfo(String seInfo);
 
-    ParsedPackage setSeInfoUser(String seInfoUser);
-
     ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir);
 
     /**
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
index 728e1bc..c7dc267 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
@@ -16,484 +16,91 @@
 
 package com.android.server.pm.parsing.pkg;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
-import android.util.SparseArray;
+import android.content.pm.parsing.PkgWithoutStateAppInfo;
 
-import com.android.internal.R;
+import com.android.server.pm.PackageManagerService;
 
 /**
- * Container for fields that are eventually exposed through {@link ApplicationInfo}.
- *
- * Done to separate the meaningless, re-directed JavaDoc for methods and to separate what's
- * exposed vs not exposed to core.
- *
- * @hide
+ * Equivalent of {@link PkgWithoutStateAppInfo} but contains fields that are set inside {@link
+ * PackageManagerService} and thus are not available to the core SDK.
+ * <p>
+ * Everything in this interface is @SystemApi(client = SYSTEM_SERVER), but the interface itself is
+ * not.
  */
-interface PkgAppInfo {
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE */
-    boolean isCantSaveState();
+public interface PkgAppInfo extends PkgWithoutStateAppInfo {
 
     /**
-     * @see ApplicationInfo#appComponentFactory
-     * @see R.styleable#AndroidManifestApplication_appComponentFactory
+     * @see ApplicationInfo#nativeLibraryDir
      */
     @Nullable
-    String getAppComponentFactory();
-
-    /**
-     * @see ApplicationInfo#backupAgentName
-     * @see R.styleable#AndroidManifestApplication_backupAgent
-     */
-    @Nullable
-    String getBackupAgentName();
-
-    /**
-     * @see ApplicationInfo#banner
-     * @see R.styleable#AndroidManifestApplication_banner
-     */
-    int getBanner();
-
-    /**
-     * @see ApplicationInfo#category
-     * @see R.styleable#AndroidManifestApplication_appCategory
-     */
-    int getCategory();
-
-    /**
-     * @see ApplicationInfo#classLoaderName
-     * @see R.styleable#AndroidManifestApplication_classLoader
-     */
-    @Nullable
-    String getClassLoaderName();
-
-    /**
-     * @see ApplicationInfo#className
-     * @see R.styleable#AndroidManifestApplication_name
-     */
-    @Nullable
-    String getClassName();
-
-    /**
-     * @see ApplicationInfo#compatibleWidthLimitDp
-     * @see R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp
-     */
-    int getCompatibleWidthLimitDp();
-
-    /**
-     * @see ApplicationInfo#compileSdkVersion
-     * @see R.styleable#AndroidManifest_compileSdkVersion
-     */
-    int getCompileSdkVersion();
-
-    /**
-     * @see ApplicationInfo#compileSdkVersionCodename
-     * @see R.styleable#AndroidManifest_compileSdkVersionCodename
-     */
-    @Nullable
-    String getCompileSdkVersionCodeName();
-
-    /**
-     * @see ApplicationInfo#descriptionRes
-     * @see R.styleable#AndroidManifestApplication_description
-     */
-    int getDescriptionRes();
-
-    /**
-     * @see ApplicationInfo#fullBackupContent
-     * @see R.styleable#AndroidManifestApplication_fullBackupContent
-     */
-    int getFullBackupContent();
-
-    /**
-     * @see ApplicationInfo#iconRes
-     * @see R.styleable#AndroidManifestApplication_icon
-     */
-    int getIconRes();
-
-    /**
-     * @see ApplicationInfo#labelRes
-     * @see R.styleable#AndroidManifestApplication_label
-     */
-    int getLabelRes();
-
-    /**
-     * @see ApplicationInfo#largestWidthLimitDp
-     * @see R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
-     */
-    int getLargestWidthLimitDp();
-
-    /**
-     * @see ApplicationInfo#logo
-     * @see R.styleable#AndroidManifestApplication_logo
-     */
-    int getLogo();
-
-    /**
-     * @see ApplicationInfo#manageSpaceActivityName
-     * @see R.styleable#AndroidManifestApplication_manageSpaceActivity
-     */
-    @Nullable
-    String getManageSpaceActivityName();
-
-    /**
-     * @see ApplicationInfo#maxAspectRatio
-     * @see R.styleable#AndroidManifestApplication_maxAspectRatio
-     */
-    float getMaxAspectRatio();
-
-    /**
-     * @see ApplicationInfo#minAspectRatio
-     * @see R.styleable#AndroidManifestApplication_minAspectRatio
-     */
-    float getMinAspectRatio();
-
-    /**
-     * @see ApplicationInfo#minSdkVersion
-     * @see R.styleable#AndroidManifestUsesSdk_minSdkVersion
-     */
-    int getMinSdkVersion();
-
-    /** @see ApplicationInfo#nativeLibraryDir */
-    @Nullable
     String getNativeLibraryDir();
 
-    /** @see ApplicationInfo#nativeLibraryRootDir */
+    /**
+     * @see ApplicationInfo#nativeLibraryRootDir
+     */
     @Nullable
     String getNativeLibraryRootDir();
 
     /**
-     * @see ApplicationInfo#networkSecurityConfigRes
-     * @see R.styleable#AndroidManifestApplication_networkSecurityConfig
+     * @see ApplicationInfo#secondaryNativeLibraryDir
      */
-    int getNetworkSecurityConfigRes();
-
-    /**
-     * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
-     * Otherwise, it's stored as {@link #getLabelRes()}.
-     * @see ApplicationInfo#nonLocalizedLabel
-     * @see R.styleable#AndroidManifestApplication_label
-     */
-    @Nullable
-    CharSequence getNonLocalizedLabel();
-
-    /**
-     * @see ApplicationInfo#permission
-     * @see R.styleable#AndroidManifestApplication_permission
-     */
-    @Nullable
-    String getPermission();
-
-    /**
-     * TODO(b/135203078): Hide this in the utility, should never be accessed directly
-     * @see ApplicationInfo#primaryCpuAbi
-     */
-    @Nullable
-    String getPrimaryCpuAbi();
-
-    /**
-     * @see ApplicationInfo#processName
-     * @see R.styleable#AndroidManifestApplication_process
-     */
-    @NonNull
-    String getProcessName();
-
-    /**
-     * @see ApplicationInfo#requiresSmallestWidthDp
-     * @see R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
-     */
-    int getRequiresSmallestWidthDp();
-
-    /**
-     * @see ApplicationInfo#roundIconRes
-     * @see R.styleable#AndroidManifestApplication_roundIcon
-     */
-    int getRoundIconRes();
-
-    /**
-     * @see ApplicationInfo#areAttributionsUserVisible()
-     * @see R.styleable#AndroidManifestApplication_attributionsAreUserVisible
-     */
-    boolean areAttributionsUserVisible();
-
-    /** @see ApplicationInfo#seInfo */
-    @Nullable
-    String getSeInfo();
-
-    /** @see ApplicationInfo#seInfoUser */
-    @Nullable
-    String getSeInfoUser();
-
-    /** @see ApplicationInfo#secondaryCpuAbi */
-    @Nullable
-    String getSecondaryCpuAbi();
-
-    /** @see ApplicationInfo#secondaryNativeLibraryDir */
     @Nullable
     String getSecondaryNativeLibraryDir();
 
     /**
-     * @see ApplicationInfo#installLocation
-     * @see R.styleable#AndroidManifest_installLocation
+     * @see ApplicationInfo#uid
      */
-    int getInstallLocation();
-
-    /**
-     * @see ApplicationInfo#splitClassLoaderNames
-     * @see R.styleable#AndroidManifestApplication_classLoader
-     */
-    @Nullable
-    String[] getSplitClassLoaderNames();
-
-    /** @see ApplicationInfo#splitSourceDirs */
-    @Nullable
-    String[] getSplitCodePaths();
-
-    /** @see ApplicationInfo#splitDependencies */
-    @Nullable
-    SparseArray<int[]> getSplitDependencies();
-
-    /**
-     * @see ApplicationInfo#targetSandboxVersion
-     * @see R.styleable#AndroidManifest_targetSandboxVersion
-     */
-    @Deprecated
-    int getTargetSandboxVersion();
-
-    /**
-     * @see ApplicationInfo#targetSdkVersion
-     * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion
-     */
-    int getTargetSdkVersion();
-
-    /**
-     * @see ApplicationInfo#taskAffinity
-     * @see R.styleable#AndroidManifestApplication_taskAffinity
-     */
-    @Nullable
-    String getTaskAffinity();
-
-    /**
-     * @see ApplicationInfo#theme
-     * @see R.styleable#AndroidManifestApplication_theme
-     */
-    int getTheme();
-
-    /**
-     * @see ApplicationInfo#uiOptions
-     * @see R.styleable#AndroidManifestApplication_uiOptions
-     */
-    int getUiOptions();
-
-    /** @see ApplicationInfo#uid */
     int getUid();
 
-    /** @see ApplicationInfo#longVersionCode */
-    long getLongVersionCode();
-
-    /** @see ApplicationInfo#versionCode */
-    @Deprecated
-    int getVersionCode();
-
-    /** @see ApplicationInfo#volumeUuid */
-    @Nullable
-    String getVolumeUuid();
-
-    /** @see ApplicationInfo#zygotePreloadName */
-    @Nullable
-    String getZygotePreloadName();
-
-    /** @see ApplicationInfo#FLAG_HAS_CODE */
-    boolean isHasCode();
-
-    /** @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING */
-    boolean isAllowTaskReparenting();
-
-    /** @see ApplicationInfo#FLAG_MULTIARCH */
-    boolean isMultiArch();
-
-    /** @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS */
-    boolean isExtractNativeLibs();
-
-    /** @see ApplicationInfo#FLAG_DEBUGGABLE */
-    boolean isDebuggable();
-
-    /** @see ApplicationInfo#FLAG_VM_SAFE_MODE */
-    boolean isVmSafeMode();
-
-    /** @see ApplicationInfo#FLAG_PERSISTENT */
-    boolean isPersistent();
-
-    /** @see ApplicationInfo#FLAG_ALLOW_BACKUP */
-    boolean isAllowBackup();
-
-    /** @see ApplicationInfo#FLAG_TEST_ONLY */
-    boolean isTestOnly();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION */
-    boolean isResizeableActivityViaSdkVersion();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */
-    boolean isHasDomainUrls();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE */
-    boolean isRequestLegacyExternalStorage();
-
-    /** @see ApplicationInfo#FLAG_HARDWARE_ACCELERATED */
-    boolean isBaseHardwareAccelerated();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE */
-    boolean isDefaultToDeviceProtectedStorage();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_DIRECT_BOOT_AWARE */
-    boolean isDirectBootAware();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE */
-    boolean isPartiallyDirectBootAware();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX */
-    boolean isUseEmbeddedDex();
-
-    /** @see ApplicationInfo#FLAG_EXTERNAL_STORAGE */
-    boolean isExternalStorage();
-
-    /** @see ApplicationInfo#nativeLibraryRootRequiresIsa */
-    boolean isNativeLibraryRootRequiresIsa();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ODM */
-    boolean isOdm();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_OEM */
-    boolean isOem();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_PRIVILEGED */
-    boolean isPrivileged();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_PRODUCT */
-    boolean isProduct();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_PROFILEABLE_BY_SHELL */
-    boolean isProfileableByShell();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_STATIC_SHARED_LIBRARY */
-    boolean isStaticSharedLibrary();
-
-    /** @see ApplicationInfo#FLAG_SYSTEM */
-    boolean isSystem();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_SYSTEM_EXT */
-    boolean isSystemExt();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_VENDOR */
-    boolean isVendor();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING */
-    boolean isIsolatedSplitLoading();
-
     /**
-     * @see ApplicationInfo#enabled
-     * @see R.styleable#AndroidManifestApplication_enabled
+     * @see ApplicationInfo#FLAG_FACTORY_TEST
      */
-    boolean isEnabled();
-
-    /**
-     * @see ApplicationInfo#PRIVATE_FLAG_IS_RESOURCE_OVERLAY
-     * @see ApplicationInfo#isResourceOverlay()
-     */
-    boolean isOverlay();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API */
-    boolean isUsesNonSdkApi();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY */
-    boolean isSignedWithPlatformKey();
-
-    /** @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE */
-    boolean isKillAfterRestore();
-
-    /** @see ApplicationInfo#FLAG_RESTORE_ANY_VERSION */
-    boolean isRestoreAnyVersion();
-
-    /** @see ApplicationInfo#FLAG_FULL_BACKUP_ONLY */
-    boolean isFullBackupOnly();
-
-    /** @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA */
-    boolean isAllowClearUserData();
-
-    /** @see ApplicationInfo#FLAG_LARGE_HEAP */
-    boolean isLargeHeap();
-
-    /** @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC */
-    boolean isUsesCleartextTraffic();
-
-    /** @see ApplicationInfo#FLAG_SUPPORTS_RTL */
-    boolean isSupportsRtl();
-
-    /** @see ApplicationInfo#FLAG_IS_GAME */
-    @Deprecated
-    boolean isGame();
-
-    /** @see ApplicationInfo#FLAG_FACTORY_TEST */
     boolean isFactoryTest();
 
     /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_smallScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
+     * @see ApplicationInfo#nativeLibraryRootRequiresIsa
      */
-    boolean isSupportsSmallScreens();
+    boolean isNativeLibraryRootRequiresIsa();
 
     /**
-     * If omitted from manifest, returns true.
-     * @see R.styleable#AndroidManifestSupportsScreens_normalScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
+     * @see ApplicationInfo#PRIVATE_FLAG_ODM
      */
-    boolean isSupportsNormalScreens();
+    boolean isOdm();
 
     /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_largeScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
+     * @see ApplicationInfo#PRIVATE_FLAG_OEM
      */
-    boolean isSupportsLargeScreens();
+    boolean isOem();
 
     /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#GINGERBREAD}.
-     * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
-     * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
+     * @see ApplicationInfo#PRIVATE_FLAG_PRIVILEGED
      */
-    boolean isSupportsExtraLargeScreens();
+    boolean isPrivileged();
 
     /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_resizeable
-     * @see ApplicationInfo#FLAG_RESIZEABLE_FOR_SCREENS
+     * @see ApplicationInfo#PRIVATE_FLAG_PRODUCT
      */
-    boolean isResizeable();
+    boolean isProduct();
 
     /**
-     * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >=
-     * {@link android.os.Build.VERSION_CODES#DONUT}.
-     * @see R.styleable#AndroidManifestSupportsScreens_anyDensity
-     * @see ApplicationInfo#FLAG_SUPPORTS_SCREEN_DENSITIES
+     * @see ApplicationInfo#PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY
      */
-    boolean isAnyDensity();
+    boolean isSignedWithPlatformKey();
 
-    /** @see ApplicationInfo#PRIVATE_FLAG_BACKUP_IN_FOREGROUND */
-    boolean isBackupInForeground();
+    /**
+     * @see ApplicationInfo#FLAG_SYSTEM
+     */
+    boolean isSystem();
 
-    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE */
-    boolean isAllowClearUserDataOnFailedRestore();
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_SYSTEM_EXT
+     */
+    boolean isSystemExt();
 
-    /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE */
-    boolean isAllowAudioPlaybackCapture();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA */
-    boolean isHasFragileUserData();
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_VENDOR
+     */
+    boolean isVendor();
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
index 89330a9..b3b3910 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
@@ -16,143 +16,27 @@
 
 package com.android.server.pm.parsing.pkg;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.FeatureGroupInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.PkgWithoutStatePackageInfo;
 
-import com.android.internal.R;
-
-import java.util.List;
+import com.android.server.pm.PackageManagerService;
 
 /**
- * Container for fields that are eventually exposed through {@link PackageInfo}.
- *
- * Done to separate the meaningless, re-directed JavaDoc for methods and to separate what's
- * exposed vs not exposed to core.
- *
- * @hide
+ * Equivalent of {@link PkgWithoutStatePackageInfo} but contains fields that are set inside {@link
+ * PackageManagerService} and thus are not available to the core SDK.
+ * <p>
+ * Everything in this interface is @SystemApi(client = SYSTEM_SERVER), but the interface itself is
+ * not.
  */
-interface PkgPackageInfo {
+public interface PkgPackageInfo extends PkgWithoutStatePackageInfo {
 
     /**
-     * @see PackageInfo#overlayCategory
-     * @see R.styleable#AndroidManifestResourceOverlay_category
-     */
-    @Nullable
-    String getOverlayCategory();
-
-    /**
-     * @see PackageInfo#overlayPriority
-     * @see R.styleable#AndroidManifestResourceOverlay_priority
-     */
-    int getOverlayPriority();
-
-    /**
-     * @see PackageInfo#overlayTarget
-     * @see R.styleable#AndroidManifestResourceOverlay_targetPackage
-     */
-    @Nullable
-    String getOverlayTarget();
-
-    /**
-     * @see PackageInfo#targetOverlayableName
-     * @see R.styleable#AndroidManifestResourceOverlay_targetName
-     */
-    @Nullable
-    String getOverlayTargetName();
-
-    /**
-     * @see PackageInfo#sharedUserId
-     * @see R.styleable#AndroidManifest_sharedUserId
-     */
-    @Deprecated
-    @Nullable
-    String getSharedUserId();
-
-    /**
-     * @see PackageInfo#sharedUserLabel
-     * @see R.styleable#AndroidManifest_sharedUserLabel
-     */
-    @Deprecated
-    int getSharedUserLabel();
-
-    /**
-     * The required account type without which this application will not function.
+     * For marking packages required for a minimal boot state, through the "coreApp" manifest
+     * attribute.
      *
-     * @see PackageInfo#requiredAccountType
-     * @see R.styleable#AndroidManifestApplication_requiredAccountType
+     * @see PackageInfo#coreApp
      */
-    @Nullable
-    String getRequiredAccountType();
-
-    /**
-     * The restricted account authenticator type that is used by this application
-     *
-     * @see PackageInfo#restrictedAccountType
-     * @see R.styleable#AndroidManifestApplication_restrictedAccountType
-     */
-    @Nullable
-    String getRestrictedAccountType();
-
-    /** @see PackageInfo#splitRevisionCodes */
-    int[] getSplitRevisionCodes();
-
-    /** @see PackageInfo#getLongVersionCode() */
-    long getLongVersionCode();
-
-    /** @see PackageInfo#versionCode */
-    @Deprecated
-    int getVersionCode();
-
-    /** @see PackageInfo#versionCodeMajor */
-    int getVersionCodeMajor();
-
-    /** @see PackageInfo#versionName */
-    @Nullable
-    String getVersionName();
-
-    /** @see PackageInfo#mOverlayIsStatic */
-    boolean isOverlayIsStatic();
-
-    /**
-     * @see PackageInfo#requiredForAllUsers
-     * @see R.styleable#AndroidManifestApplication_requiredForAllUsers
-     */
-    boolean isRequiredForAllUsers();
-
-    /**
-     * @see PackageInfo#reqFeatures
-     * @see R.styleable#AndroidManifestUsesFeature
-     */
-    @NonNull
-    List<FeatureInfo> getReqFeatures();
-
-    /**
-     * @see PackageInfo#configPreferences
-     * @see R.styleable#AndroidManifestUsesConfiguration
-     */
-    @NonNull
-    List<ConfigurationInfo> getConfigPreferences();
-
-    /**
-     * @see PackageInfo#featureGroups
-     * @see R.styleable#AndroidManifestUsesFeature
-     */
-    @NonNull
-    List<FeatureGroupInfo> getFeatureGroups();
+    boolean isCoreApp();
 
     /**
      * Whether or not the package is a stub and must be replaced by the full version.
@@ -160,66 +44,4 @@
      * @see PackageInfo#isStub
      */
     boolean isStub();
-
-    /**
-     * For marking packages required for a minimal boot state, through the "coreApp" manifest
-     * attribute.
-     * @see PackageInfo#coreApp
-     */
-    boolean isCoreApp();
-
-    /**
-     * All the permissions declared. This is an effective set, and may include permissions
-     * transformed from split/migrated permissions from previous versions, so may not be exactly
-     * what the package declares in its manifest.
-     * @see PackageInfo#requestedPermissions
-     * @see R.styleable#AndroidManifestUsesPermission
-     */
-    @NonNull
-    List<String> getRequestedPermissions();
-
-    /**
-     * @see ActivityInfo
-     * @see PackageInfo#activities
-     */
-    @NonNull
-    List<ParsedActivity> getActivities();
-
-    /**
-     * @see InstrumentationInfo
-     * @see PackageInfo#instrumentation
-     */
-    @NonNull
-    List<ParsedInstrumentation> getInstrumentations();
-
-    /**
-     * @see PermissionInfo
-     * @see PackageInfo#permissions
-     */
-    @NonNull
-    List<ParsedPermission> getPermissions();
-
-    /**
-     * @see ProviderInfo
-     * @see PackageInfo#providers
-     */
-    @NonNull
-    List<ParsedProvider> getProviders();
-
-    /**
-     * Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even
-     * though they represent different functionality.
-     * TODO(b/135203078): Reconsider this and maybe make ParsedReceiver so it's not so confusing
-     * @see ActivityInfo
-     * @see PackageInfo#receivers
-     */
-    @NonNull
-    List<ParsedActivity> getReceivers();
-
-    /**
-     * @see ServiceInfo
-     * @see PackageInfo#services
-     */
-    @NonNull
-    List<ParsedService> getServices();
 }
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index dd50b0c..4bbe373 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -33,7 +33,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.PermissionThread;
 
 /**
  * Class that handles one-time permissions for a user
@@ -80,8 +79,7 @@
         mContext = context;
         mActivityManager = context.getSystemService(ActivityManager.class);
         mAlarmManager = context.getSystemService(AlarmManager.class);
-        mPermissionControllerManager = new PermissionControllerManager(
-                mContext, PermissionThread.getHandler());
+        mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class);
         mHandler = context.getMainThreadHandler();
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index b1b46af..75f3725 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -476,9 +476,10 @@
             r.append("DUP:");
             r.append(permissionInfo.name);
         }
-        if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
-            // If this is a runtime permission and the owner has changed, or this wasn't a runtime
-            // permission, then permission state should be cleaned up
+        if ((permission.isInternal() && ownerChanged)
+                || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
+            // If this is an internal/runtime permission and the owner has changed, or this wasn't a
+            // runtime permission, then permission state should be cleaned up.
             permission.mDefinitionChanged = true;
         }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
@@ -497,13 +498,10 @@
                 if (permissionTree.getUid() == UserHandle.getAppId(callingUid)) {
                     return permissionTree;
                 }
-                throw new SecurityException("Calling uid " + callingUid
-                        + " is not allowed to add to permission tree "
-                        + permissionTree.getName() + " owned by uid "
-                        + permissionTree.getUid());
             }
         }
-        throw new SecurityException("No permission tree found for " + permissionName);
+        throw new SecurityException("Calling uid " + callingUid
+            + " is not allowed to add to or remove from the permission tree");
     }
 
     @Nullable
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 919ed5f..de1e25a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -145,7 +145,6 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.PermissionThread;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
@@ -155,6 +154,7 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener;
 import com.android.server.policy.PermissionPolicyInternal;
@@ -219,6 +219,8 @@
 
     /** All storage permissions */
     private static final List<String> STORAGE_PERMISSIONS = new ArrayList<>();
+    /** All nearby devices permissions */
+    private static final List<String> NEARBY_DEVICES_PERMISSIONS = new ArrayList<>();
 
     /** If the permission of the value is granted, so is the key */
     private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();
@@ -235,6 +237,9 @@
         STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
         STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
         STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
+        NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_ADVERTISE);
+        NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT);
+        NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN);
     }
 
     /** Set of source package names for Privileged Permission Allowlist */
@@ -1212,6 +1217,7 @@
 
     private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(
             @NonNull String permName) {
+        final String permissionPackageName;
         final boolean isImmutablyRestrictedPermission;
         synchronized (mLock) {
             final Permission bp = mRegistry.getPermission(permName);
@@ -1219,15 +1225,25 @@
                 Slog.w(TAG, "No such permissions: " + permName);
                 return false;
             }
+            permissionPackageName = bp.getPackageName();
             isImmutablyRestrictedPermission = bp.isHardOrSoftRestricted()
                     && bp.isImmutablyRestricted();
         }
+
+        final int callingUid = getCallingUid();
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (mPackageManagerInt.filterAppAccess(permissionPackageName, callingUid, callingUserId)) {
+            EventLog.writeEvent(0x534e4554, "186404356", callingUid, permName);
+            return false;
+        }
+
         if (isImmutablyRestrictedPermission && mContext.checkCallingOrSelfPermission(
                 Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Cannot modify allowlisting of an immutably "
                     + "restricted permission: " + permName);
         }
+
         return true;
     }
 
@@ -1470,7 +1486,8 @@
                 && mayManageRolePermission(callingUid);
         final boolean mayGrantSoftRestrictedPermission = isSoftRestrictedPermission
                 && SoftRestrictedPermissionPolicy.forPermission(mContext,
-                        pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName)
+                        AndroidPackageUtils.generateAppInfoWithoutState(pkg), pkg,
+                        UserHandle.of(userId), permName)
                         .mayGrantPermission();
 
         final boolean isRuntimePermission;
@@ -1640,7 +1657,8 @@
             isRolePermission = permission.isRole();
         }
         final boolean mayRevokeRolePermission = isRolePermission
-                && mayManageRolePermission(callingUid);
+                // Allow ourselves to revoke role permissions due to definition changes.
+                && (callingUid == Process.myUid() || mayManageRolePermission(callingUid));
 
         final boolean isRuntimePermission;
         synchronized (mLock) {
@@ -2057,7 +2075,7 @@
     private byte[] backupRuntimePermissions(@UserIdInt int userId) {
         CompletableFuture<byte[]> backup = new CompletableFuture<>();
         mPermissionControllerManager.getRuntimePermissionBackup(UserHandle.of(userId),
-                PermissionThread.getExecutor(), backup::complete);
+                mContext.getMainExecutor(), backup::complete);
 
         try {
             return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
@@ -2102,7 +2120,7 @@
             }
         }
         mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName,
-                UserHandle.of(userId), PermissionThread.getExecutor(), (hasMoreBackup) -> {
+                UserHandle.of(userId), mContext.getMainExecutor(), (hasMoreBackup) -> {
                     if (hasMoreBackup) {
                         return;
                     }
@@ -2318,11 +2336,13 @@
 
         for (int permNum = 0; permNum < numPermissions; permNum++) {
             final String permName = permissionsToRevoke.get(permNum);
+            final boolean isInternalPermission;
             synchronized (mLock) {
                 final Permission bp = mRegistry.getPermission(permName);
-                if (bp == null || !bp.isRuntime()) {
+                if (bp == null || !(bp.isInternal() || bp.isRuntime())) {
                     continue;
                 }
+                isInternalPermission = bp.isInternal();
             }
             mPackageManagerInt.forEachPackage(pkg -> {
                 final String packageName = pkg.getPackageName();
@@ -2342,12 +2362,18 @@
                     if (permissionState == PackageManager.PERMISSION_GRANTED
                             && (flags & flagMask) == 0) {
                         final int uid = UserHandle.getUid(userId, appId);
-                        EventLog.writeEvent(0x534e4554, "154505240", uid,
-                                "Revoking permission " + permName + " from package "
-                                        + packageName + " due to definition change");
-                        EventLog.writeEvent(0x534e4554, "168319670", uid,
-                                "Revoking permission " + permName + " from package "
-                                        + packageName + " due to definition change");
+                        if (isInternalPermission) {
+                            EventLog.writeEvent(0x534e4554, "195338390", uid,
+                                    "Revoking permission " + permName + " from package "
+                                            + packageName + " due to definition change");
+                        } else {
+                            EventLog.writeEvent(0x534e4554, "154505240", uid,
+                                    "Revoking permission " + permName + " from package "
+                                            + packageName + " due to definition change");
+                            EventLog.writeEvent(0x534e4554, "168319670", uid,
+                                    "Revoking permission " + permName + " from package "
+                                            + packageName + " due to definition change");
+                        }
                         Slog.e(TAG, "Revoking permission " + permName + " from package "
                                 + packageName + " due to definition change");
                         try {
@@ -3078,13 +3104,26 @@
                 Permission bp = mRegistry.getPermission(permission);
                 if (bp != null && bp.isRuntime()) {
                     int flags = ps.getPermissionFlags(permission);
-
                     if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
-
                         int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
 
+                        // We're willing to preserve an implicit "Nearby devices"
+                        // permission grant if this app was already able to interact
+                        // with nearby devices via background location access
+                        boolean preserveGrant = false;
+                        if (ArrayUtils.contains(NEARBY_DEVICES_PERMISSIONS, permission)
+                                && ps.isPermissionGranted(
+                                        android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)
+                                && (ps.getPermissionFlags(
+                                        android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)
+                                        & (FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
+                                                | FLAG_PERMISSION_REVOKED_COMPAT)) == 0) {
+                            preserveGrant = true;
+                        }
+
                         if ((flags & BLOCKING_PERMISSION_FLAGS) == 0
-                                && supportsRuntimePermissions) {
+                                && supportsRuntimePermissions
+                                && !preserveGrant) {
                             if (ps.revokePermission(bp)) {
                                 if (DEBUG_PERMISSIONS) {
                                     Slog.i(TAG, "Revoking runtime permission "
@@ -4551,8 +4590,7 @@
             }
         }
 
-        mPermissionControllerManager = new PermissionControllerManager(
-                mContext, PermissionThread.getHandler());
+        mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
         mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
     }
 
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java b/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
new file mode 100644
index 0000000..3fde41a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
@@ -0,0 +1,36 @@
+/*
+ * 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.pm.pkg;
+
+import android.annotation.SystemApi;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PkgAppInfo;
+import com.android.server.pm.parsing.pkg.PkgPackageInfo;
+
+/**
+ * Explicit interface used for consumers like mainline who need a {@link SystemApi @SystemApi} form
+ * of {@link AndroidPackage}.
+ * <p>
+ * There should be no methods in this class. All of them must come from other interfaces that group
+ * the actual methods. This is done to ensure proper separation of the (legacy?) Info object APIs.
+ */
+// TODO(b/173807334): Expose API
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface AndroidPackageApi extends PkgPackageInfo, PkgAppInfo {
+
+}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
new file mode 100644
index 0000000..0d29bab
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -0,0 +1,277 @@
+/*
+ * 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.pm.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningInfo;
+import android.content.pm.pkg.PackageUserState;
+
+import com.android.internal.R;
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.Settings;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The API surface for a {@link PackageSetting}. Methods are expected to return immutable objects.
+ * This may mean copying data on each invocation until related classes are refactored to be
+ * immutable.
+ * <p>
+ * Note that until immutability or read-only caching is enabled, {@link PackageSetting} cannot be
+ * returned directly, so {@link PackageStateImpl} is used to temporarily copy the data. This is a
+ * relatively expensive operation since it has to create an object for every package, but it's much
+ * lighter than the alternative of generating {@link PackageInfo} objects.
+ * <p>
+ * TODO: Documentation TODO: Currently missing, should be exposed as API?
+ * <ul>
+ *     <li>keySetData</li>
+ *     <li>installSource</li>
+ *     <li>incrementalStates</li>
+ * </ul>
+ *
+ * @hide
+ *
+ * TODO(chiuwinson): Delete all of the method defaults
+ */
+// TODO(b/173807334): Expose API
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface PackageState {
+
+    /**
+     * This can be null whenever a physical APK on device is missing. This can be the result of
+     * removing an external storage device where the APK resides.
+     * <p>
+     * This will result in the system reading the {@link PackageSetting} from disk, but without
+     * being able to parse the base APK's AndroidManifest.xml to read all of its metadata. The data
+     * that is written and read in {@link Settings} includes a minimal set of metadata needed to
+     * perform other checks in the system.
+     * <p>
+     * This is important in order to enforce uniqueness within the system, as the package, even if
+     * on a removed storage device, is still considered installed. Another package of the same
+     * application ID or declaring the same permissions or similar cannot be installed.
+     * <p>
+     * Re-attaching the storage device to make the APK available should allow the user to use the
+     * app once the device reboots or otherwise re-scans it.
+     */
+    @Nullable
+    default AndroidPackageApi getAndroidPackage() { return null; }
+
+    /**
+     * The non-user-specific UID
+     */
+    default int getAppId() { return -1; }
+
+    /**
+     * Value set through {@link PackageManager#setApplicationCategoryHint(String, int)}. Only
+     * applied if the application itself does not declare a category.
+     *
+     * @see AndroidPackageApi#getCategory()
+     */
+    default int getCategoryOverride() { return -1; }
+
+    @Nullable
+    default String getCpuAbiOverride() { return null; }
+
+    /**
+     * In epoch milliseconds.
+     */
+    default long getFirstInstallTime() { return -1; }
+
+    /**
+     * In epoch milliseconds.
+     */
+    default long getLastModifiedTime() { return -1; }
+
+    @NonNull
+    default long[] getLastPackageUsageTime() { return null; }
+
+    /**
+     * In epoch milliseconds.
+     */
+    default long getLastUpdateTime() { return -1; }
+
+    /**
+     * @see AndroidPackageApi#getLongVersionCode()
+     */
+    default long getLongVersionCode() { return -1; }
+
+    /**
+     * Maps mime group name to the set of Mime types in a group. Mime groups declared by app are
+     * populated with empty sets at construction. Mime groups can not be created/removed at runtime,
+     * thus keys in this map should not change
+     */
+    @NonNull
+    default Map<String, Set<String>> getMimeGroups() { return null; }
+
+    /**
+     * @see AndroidPackageApi#getPackageName()
+     */
+    @NonNull
+    default String getPackageName() { return null; }
+
+    /**
+     * @see AndroidPackageApi#getPath()
+     */
+    @NonNull
+    default File getPath() { return null; }
+
+    @Nullable
+    default String getPrimaryCpuAbi() { return null; }
+
+    @Nullable
+    default String getSeInfoOverride() { return null; }
+
+    @Nullable
+    default String getSecondaryCpuAbi() { return null; }
+
+    /**
+     * Retrieves the shared user ID. Note that the actual shared user data is not available here and
+     * must be queried separately.
+     *
+     * @return the shared user this package is a part of, or null if it's not part of a shared user.
+     */
+    @Nullable
+    default Integer getSharedUserId() { return null; }
+
+    @NonNull
+    default SigningInfo getSigningInfo() { return null; }
+
+    /**
+     * Valid users for this package, for use with {@link #getUserState(int)}.
+     */
+    default int[] getUserIds() { return null; }
+
+    /**
+     * Retrieves per-user state for this package. Acceptable user IDs are in {@link #getUserIds()}.
+     */
+    @Nullable
+    default PackageUserState getUserState(@UserIdInt int userId) { return null; }
+
+    /**
+     * The actual files resolved for each shared library.
+     *
+     * @see R.styleable#AndroidManifestUsesLibrary
+     */
+    @NonNull
+    default List<String> getUsesLibraryFiles() { return null; }
+
+    /**
+     * @see R.styleable#AndroidManifestUsesLibrary
+     */
+    @NonNull
+    default List<SharedLibraryInfo> getUsesLibraryInfos() { return null; }
+
+    /**
+     * @see R.styleable#AndroidManifestUsesStaticLibrary
+     */
+    @NonNull
+    default String[] getUsesStaticLibraries() { return null; }
+
+    /**
+     * @see R.styleable#AndroidManifestUsesStaticLibrary_version
+     */
+    @NonNull
+    default long[] getUsesStaticLibrariesVersions() { return null; }
+
+    /**
+     * @see AndroidPackageApi#getVolumeUuid()
+     */
+    @Nullable
+    default String getVolumeUuid() { return null; }
+
+    /**
+     * @see AndroidPackageApi#isExternalStorage()
+     */
+    default boolean isExternalStorage() { return false; }
+
+    /**
+     * Whether a package was installed --force-queryable such that it is always queryable by any
+     * package, regardless of their manifest content.
+     */
+    default boolean isForceQueryableOverride() { return false; }
+
+    /**
+     * Whether a package is treated as hidden until it is installed for a user.
+     *
+     * @see PackageManager#MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+     * @see PackageManager#setSystemAppState
+     */
+    default boolean isHiddenUntilInstalled() { return false; }
+
+    default boolean isInstallPermissionsFixed() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isOdm()
+     */
+    default boolean isOdm() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isOem()
+     */
+    default boolean isOem() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isPrivileged()
+     */
+    default boolean isPrivileged() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isProduct()
+     */
+    default boolean isProduct() { return false; }
+
+    /**
+     * @see ApplicationInfo#PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER
+     */
+    default boolean isRequiredForSystemUser() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isSystem()
+     */
+    default boolean isSystem() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isSystemExt()
+     */
+    default boolean isSystemExt() { return false; }
+
+    /**
+     * Whether or not an update is available. Ostensibly only for instant apps.
+     */
+    default boolean isUpdateAvailable() { return false; }
+
+    /**
+     * Whether this app is on the /data partition having been upgraded from a preinstalled app on a
+     * system partition.
+     */
+    default boolean isUpdatedSystemApp() { return false; }
+
+    /**
+     * @see AndroidPackageApi#isVendor()
+     */
+    default boolean isVendor() { return false; }
+}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
new file mode 100644
index 0000000..6cd55c1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -0,0 +1,651 @@
+/*
+ * 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.pm.pkg;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningInfo;
+import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.pkg.PackageUserState;
+import android.util.SparseArray;
+
+import com.android.internal.util.DataClass;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.Settings;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Because a {@link PackageSetting} cannot be returned from {@link Settings} without holding the
+ * {@link PackageManagerService#mLock}, this class serves as a memory snapshot of the state of a
+ * single package, for use with {@link PackageManagerInternal#getPackageState(String)} and {@link
+ * PackageManagerInternal#forEachPackageState(boolean, Consumer)}.
+ *
+ * @hide
+ */
+@DataClass(genConstructor = false)
+@DataClass.Suppress({"mUserStates"})
+public class PackageStateImpl implements PackageState {
+
+    public static PackageState copy(@NonNull PackageSetting pkgSetting) {
+        return new PackageStateImpl(pkgSetting, pkgSetting.getPkg());
+    }
+
+    private static class Booleans {
+        @IntDef({
+                SYSTEM,
+                EXTERNAL_STORAGE,
+                PRIVILEGED,
+                OEM,
+                VENDOR,
+                PRODUCT,
+                SYSTEM_EXT,
+                REQUIRED_FOR_SYSTEM_USER,
+                ODM,
+                FORCE_QUERYABLE_OVERRIDE,
+                HIDDEN_UNTIL_INSTALLED,
+                INSTALL_PERMISSIONS_FIXED,
+                UPDATE_AVAILABLE,
+                UPDATED_SYSTEM_APP,
+        })
+        public @interface Flags {
+        }
+
+        private static final int SYSTEM = 1;
+        private static final int EXTERNAL_STORAGE = 1 << 1;
+        private static final int PRIVILEGED = 1 << 2;
+        private static final int OEM = 1 << 3;
+        private static final int VENDOR = 1 << 4;
+        private static final int PRODUCT = 1 << 5;
+        private static final int SYSTEM_EXT = 1 << 6;
+        private static final int REQUIRED_FOR_SYSTEM_USER = 1 << 7;
+        private static final int ODM = 1 << 8;
+        private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 9;
+        private static final int HIDDEN_UNTIL_INSTALLED = 1 << 10;
+        private static final int INSTALL_PERMISSIONS_FIXED = 1 << 11;
+        private static final int UPDATE_AVAILABLE = 1 << 12;
+        private static final int UPDATED_SYSTEM_APP = 1 << 13;
+    }
+
+    private int mBooleans;
+
+    private void setBoolean(@Booleans.Flags int flag, boolean value) {
+        if (value) {
+            mBooleans |= flag;
+        } else {
+            mBooleans &= ~flag;
+        }
+    }
+
+    private boolean getBoolean(@Booleans.Flags int flag) {
+        return (mBooleans & flag) != 0;
+    }
+
+    @Nullable
+    private final AndroidPackageApi mAndroidPackage;
+
+    @NonNull
+    private final String mPackageName;
+    @Nullable
+    private final String mVolumeUuid;
+    private final int mAppId;
+    private final int mCategoryOverride;
+    @Nullable
+    private final String mCpuAbiOverride;
+    private final long mFirstInstallTime;
+    private final long mLastModifiedTime;
+    private final long mLastUpdateTime;
+    private final long mLongVersionCode;
+    @NonNull
+    private final Map<String, Set<String>> mMimeGroups;
+    @NonNull
+    private final File mPath;
+    @Nullable
+    private final String mPrimaryCpuAbi;
+    @Nullable
+    private final String mSecondaryCpuAbi;
+    @Nullable
+    private final Integer mSharedUserId;
+    @NonNull
+    private final String[] mUsesStaticLibraries;
+    @NonNull
+    private final long[] mUsesStaticLibrariesVersions;
+    @NonNull
+    private final List<SharedLibraryInfo> mUsesLibraryInfos;
+    @NonNull
+    private final List<String> mUsesLibraryFiles;
+    @Nullable
+    private final String mSeInfoOverride;
+    @NonNull
+    private final long[] mLastPackageUsageTime;
+    @NonNull
+    private final SigningInfo mSigningInfo;
+    @NonNull
+    private final int[] mUserIds;
+    @NonNull
+    private final SparseArray<PackageUserState> mUserStates;
+
+    private PackageStateImpl(@NonNull PackageState pkgState, @Nullable AndroidPackage pkg) {
+        mAndroidPackage = pkg;
+
+        setBoolean(Booleans.SYSTEM, pkgState.isSystem());
+        setBoolean(Booleans.EXTERNAL_STORAGE, pkgState.isExternalStorage());
+        setBoolean(Booleans.PRIVILEGED, pkgState.isPrivileged());
+        setBoolean(Booleans.OEM, pkgState.isOem());
+        setBoolean(Booleans.VENDOR, pkgState.isVendor());
+        setBoolean(Booleans.PRODUCT, pkgState.isProduct());
+        setBoolean(Booleans.SYSTEM_EXT, pkgState.isSystemExt());
+        setBoolean(Booleans.REQUIRED_FOR_SYSTEM_USER, pkgState.isRequiredForSystemUser());
+        setBoolean(Booleans.ODM, pkgState.isOdm());
+
+        mPackageName = pkgState.getPackageName();
+        mVolumeUuid = pkgState.getVolumeUuid();
+        mAppId = pkgState.getAppId();
+        mCategoryOverride = pkgState.getCategoryOverride();
+        mCpuAbiOverride = pkgState.getCpuAbiOverride();
+        mFirstInstallTime = pkgState.getFirstInstallTime();
+        mLastModifiedTime = pkgState.getLastModifiedTime();
+        mLastUpdateTime = pkgState.getLastUpdateTime();
+        mLongVersionCode = pkgState.getLongVersionCode();
+        mMimeGroups = pkgState.getMimeGroups();
+        mPath = pkgState.getPath();
+        mPrimaryCpuAbi = pkgState.getPrimaryCpuAbi();
+        mSecondaryCpuAbi = pkgState.getSecondaryCpuAbi();
+        mSharedUserId = pkgState.getSharedUserId();
+        mUsesStaticLibraries = pkgState.getUsesStaticLibraries();
+        mUsesStaticLibrariesVersions = pkgState.getUsesStaticLibrariesVersions();
+        mUsesLibraryInfos = pkgState.getUsesLibraryInfos();
+        mUsesLibraryFiles = pkgState.getUsesLibraryFiles();
+        setBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE, pkgState.isForceQueryableOverride());
+        setBoolean(Booleans.HIDDEN_UNTIL_INSTALLED, pkgState.isHiddenUntilInstalled());
+        setBoolean(Booleans.INSTALL_PERMISSIONS_FIXED, pkgState.isInstallPermissionsFixed());
+        setBoolean(Booleans.UPDATE_AVAILABLE, pkgState.isUpdateAvailable());
+        mSeInfoOverride = pkgState.getSeInfoOverride();
+        mLastPackageUsageTime = pkgState.getLastPackageUsageTime();
+        setBoolean(Booleans.UPDATED_SYSTEM_APP, pkgState.isUpdatedSystemApp());
+        mSigningInfo = pkgState.getSigningInfo();
+
+        mUserIds = pkgState.getUserIds();
+        mUserStates = new SparseArray<>(mUserIds.length);
+        for (int userId : mUserIds) {
+            mUserStates.put(userId, UserStateImpl.copy(pkgState.getUserState(userId)));
+        }
+    }
+
+    @Nullable
+    @Override
+    public PackageUserState getUserState(int userId) {
+        return mUserStates.get(userId);
+    }
+
+    @Override
+    public boolean isExternalStorage() {
+        return getBoolean(Booleans.EXTERNAL_STORAGE);
+    }
+
+    @Override
+    public boolean isForceQueryableOverride() {
+        return getBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE);
+    }
+
+    @Override
+    public boolean isHiddenUntilInstalled() {
+        return getBoolean(Booleans.HIDDEN_UNTIL_INSTALLED);
+    }
+
+    @Override
+    public boolean isInstallPermissionsFixed() {
+        return getBoolean(Booleans.INSTALL_PERMISSIONS_FIXED);
+    }
+
+    @Override
+    public boolean isOdm() {
+        return getBoolean(Booleans.ODM);
+    }
+
+    @Override
+    public boolean isOem() {
+        return getBoolean(Booleans.OEM);
+    }
+
+    @Override
+    public boolean isPrivileged() {
+        return getBoolean(Booleans.PRIVILEGED);
+    }
+
+    @Override
+    public boolean isProduct() {
+        return getBoolean(Booleans.PRODUCT);
+    }
+
+    @Override
+    public boolean isRequiredForSystemUser() {
+        return getBoolean(Booleans.REQUIRED_FOR_SYSTEM_USER);
+    }
+
+    @Override
+    public boolean isSystem() {
+        return getBoolean(Booleans.SYSTEM);
+    }
+
+    @Override
+    public boolean isSystemExt() {
+        return getBoolean(Booleans.SYSTEM_EXT);
+    }
+
+    @Override
+    public boolean isUpdateAvailable() {
+        return getBoolean(Booleans.UPDATE_AVAILABLE);
+    }
+
+    @Override
+    public boolean isUpdatedSystemApp() {
+        return getBoolean(Booleans.UPDATED_SYSTEM_APP);
+    }
+
+    @Override
+    public boolean isVendor() {
+        return getBoolean(Booleans.VENDOR);
+    }
+
+    /**
+     * @hide
+     */
+    @DataClass(genConstructor = false)
+    public static class UserStateImpl implements PackageUserState {
+
+        public static PackageUserState copy(@NonNull PackageUserState state) {
+            return new UserStateImpl(state);
+        }
+
+        private static class Booleans {
+            @IntDef({
+                    HIDDEN,
+                    INSTALLED,
+                    INSTANT_APP,
+                    NOT_LAUNCHED,
+                    STOPPED,
+                    SUSPENDED,
+                    VIRTUAL_PRELOAD,
+            })
+            public @interface Flags {
+            }
+
+            private static final int HIDDEN = 1;
+            private static final int INSTALLED = 1 << 1;
+            private static final int INSTANT_APP = 1 << 2;
+            private static final int NOT_LAUNCHED = 1 << 3;
+            private static final int STOPPED = 1 << 4;
+            private static final int SUSPENDED = 1 << 5;
+            private static final int VIRTUAL_PRELOAD = 1 << 6;
+        }
+
+        private int mBooleans;
+
+        private void setBoolean(@Booleans.Flags int flag, boolean value) {
+            if (value) {
+                mBooleans |= flag;
+            } else {
+                mBooleans &= ~flag;
+            }
+        }
+
+        private boolean getBoolean(@Booleans.Flags int flag) {
+            return (mBooleans & flag) != 0;
+        }
+
+        private final long mCeDataInode;
+        @NonNull
+        private final Set<String> mDisabledComponents;
+        @PackageManager.DistractionRestriction
+        private final int mDistractionFlags;
+        @NonNull
+        private final Set<String> mEnabledComponents;
+        private final int mEnabledState;
+        @Nullable
+        private final String mHarmfulAppWarning;
+        @PackageManager.InstallReason
+        private final int mInstallReason;
+        @Nullable
+        private final String mLastDisableAppCaller;
+        @NonNull
+        private final OverlayPaths mOverlayPaths;
+        @NonNull
+        private final Map<String, OverlayPaths> mSharedLibraryOverlayPaths;
+        @PackageManager.UninstallReason
+        private final int mUninstallReason;
+
+        private UserStateImpl(@NonNull PackageUserState userState) {
+            mCeDataInode = userState.getCeDataInode();
+            mDisabledComponents = userState.getDisabledComponents();
+            mDistractionFlags = userState.getDistractionFlags();
+            mEnabledComponents = userState.getEnabledComponents();
+            mEnabledState = userState.getEnabledState();
+            mHarmfulAppWarning = userState.getHarmfulAppWarning();
+            mInstallReason = userState.getInstallReason();
+            mLastDisableAppCaller = userState.getLastDisableAppCaller();
+            mOverlayPaths = userState.getOverlayPaths();
+            mSharedLibraryOverlayPaths = userState.getSharedLibraryOverlayPaths();
+            mUninstallReason = userState.getUninstallReason();
+            setBoolean(Booleans.HIDDEN, userState.isHidden());
+            setBoolean(Booleans.INSTALLED, userState.isInstalled());
+            setBoolean(Booleans.INSTANT_APP, userState.isInstantApp());
+            setBoolean(Booleans.NOT_LAUNCHED, userState.isNotLaunched());
+            setBoolean(Booleans.STOPPED, userState.isStopped());
+            setBoolean(Booleans.SUSPENDED, userState.isSuspended());
+            setBoolean(Booleans.VIRTUAL_PRELOAD, userState.isVirtualPreload());
+        }
+
+        @Override
+        public boolean isHidden() {
+            return getBoolean(Booleans.HIDDEN);
+        }
+
+        @Override
+        public boolean isInstalled() {
+            return getBoolean(Booleans.INSTALLED);
+        }
+
+        @Override
+        public boolean isInstantApp() {
+            return getBoolean(Booleans.INSTANT_APP);
+        }
+
+        @Override
+        public boolean isNotLaunched() {
+            return getBoolean(Booleans.NOT_LAUNCHED);
+        }
+
+        @Override
+        public boolean isStopped() {
+            return getBoolean(Booleans.STOPPED);
+        }
+
+        @Override
+        public boolean isSuspended() {
+            return getBoolean(Booleans.SUSPENDED);
+        }
+
+        @Override
+        public boolean isVirtualPreload() {
+            return getBoolean(Booleans.VIRTUAL_PRELOAD);
+        }
+
+
+
+        // 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/core/java/com/android/server/pm/pkg/PackageStateImpl.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 int getBooleans() {
+            return mBooleans;
+        }
+
+        @DataClass.Generated.Member
+        public long getCeDataInode() {
+            return mCeDataInode;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Set<String> getDisabledComponents() {
+            return mDisabledComponents;
+        }
+
+        @DataClass.Generated.Member
+        public @PackageManager.DistractionRestriction int getDistractionFlags() {
+            return mDistractionFlags;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Set<String> getEnabledComponents() {
+            return mEnabledComponents;
+        }
+
+        @DataClass.Generated.Member
+        public int getEnabledState() {
+            return mEnabledState;
+        }
+
+        @DataClass.Generated.Member
+        public @Nullable String getHarmfulAppWarning() {
+            return mHarmfulAppWarning;
+        }
+
+        @DataClass.Generated.Member
+        public @PackageManager.InstallReason int getInstallReason() {
+            return mInstallReason;
+        }
+
+        @DataClass.Generated.Member
+        public @Nullable String getLastDisableAppCaller() {
+            return mLastDisableAppCaller;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull OverlayPaths getOverlayPaths() {
+            return mOverlayPaths;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Map<String,OverlayPaths> getSharedLibraryOverlayPaths() {
+            return mSharedLibraryOverlayPaths;
+        }
+
+        @DataClass.Generated.Member
+        public @PackageManager.UninstallReason int getUninstallReason() {
+            return mUninstallReason;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull UserStateImpl setBooleans( int value) {
+            mBooleans = value;
+            return this;
+        }
+
+        @DataClass.Generated(
+                time = 1630602933994L,
+                codegenVersion = "1.0.23",
+                sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
+                inputSignatures = "private  int mBooleans\nprivate final  long mCeDataInode\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mDisabledComponents\nprivate final @android.content.pm.PackageManager.DistractionRestriction int mDistractionFlags\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mEnabledComponents\nprivate final  int mEnabledState\nprivate final @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate final @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate final @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate final @android.annotation.NonNull android.content.pm.overlay.OverlayPaths mOverlayPaths\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate final @android.content.pm.PackageManager.UninstallReason int mUninstallReason\npublic static  android.content.pm.pkg.PackageUserState copy(android.content.pm.pkg.PackageUserState)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isSuspended()\npublic @java.lang.Override boolean isVirtualPreload()\nclass UserStateImpl extends java.lang.Object implements [android.content.pm.pkg.PackageUserState]\nprivate static final  int HIDDEN\nprivate static final  int INSTALLED\nprivate static final  int INSTANT_APP\nprivate static final  int NOT_LAUNCHED\nprivate static final  int STOPPED\nprivate static final  int SUSPENDED\nprivate static final  int VIRTUAL_PRELOAD\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+
+
+    // 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/core/java/com/android/server/pm/pkg/PackageStateImpl.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 int getBooleans() {
+        return mBooleans;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable AndroidPackageApi getAndroidPackage() {
+        return mAndroidPackage;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getPackageName() {
+        return mPackageName;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getVolumeUuid() {
+        return mVolumeUuid;
+    }
+
+    @DataClass.Generated.Member
+    public int getAppId() {
+        return mAppId;
+    }
+
+    @DataClass.Generated.Member
+    public int getCategoryOverride() {
+        return mCategoryOverride;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getCpuAbiOverride() {
+        return mCpuAbiOverride;
+    }
+
+    @DataClass.Generated.Member
+    public long getFirstInstallTime() {
+        return mFirstInstallTime;
+    }
+
+    @DataClass.Generated.Member
+    public long getLastModifiedTime() {
+        return mLastModifiedTime;
+    }
+
+    @DataClass.Generated.Member
+    public long getLastUpdateTime() {
+        return mLastUpdateTime;
+    }
+
+    @DataClass.Generated.Member
+    public long getLongVersionCode() {
+        return mLongVersionCode;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull Map<String,Set<String>> getMimeGroups() {
+        return mMimeGroups;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull File getPath() {
+        return mPath;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getPrimaryCpuAbi() {
+        return mPrimaryCpuAbi;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getSecondaryCpuAbi() {
+        return mSecondaryCpuAbi;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable Integer getSharedUserId() {
+        return mSharedUserId;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String[] getUsesStaticLibraries() {
+        return mUsesStaticLibraries;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull long[] getUsesStaticLibrariesVersions() {
+        return mUsesStaticLibrariesVersions;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull List<SharedLibraryInfo> getUsesLibraryInfos() {
+        return mUsesLibraryInfos;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull List<String> getUsesLibraryFiles() {
+        return mUsesLibraryFiles;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getSeInfoOverride() {
+        return mSeInfoOverride;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull long[] getLastPackageUsageTime() {
+        return mLastPackageUsageTime;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull SigningInfo getSigningInfo() {
+        return mSigningInfo;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull int[] getUserIds() {
+        return mUserIds;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull SparseArray<PackageUserState> getUserStates() {
+        return mUserStates;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull PackageStateImpl setBooleans( int value) {
+        mBooleans = value;
+        return this;
+    }
+
+    @DataClass.Generated(
+            time = 1630602934025L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
+            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackageApi mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mFirstInstallTime\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.Integer mSharedUserId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.Nullable java.lang.String mSeInfoOverride\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull int[] mUserIds\nprivate final @android.annotation.NonNull android.util.SparseArray<android.content.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.PackageSetting)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @android.annotation.Nullable @java.lang.Override android.content.pm.pkg.PackageUserState getUserState(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index ba64d25..8dc02b7 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -843,7 +843,7 @@
     @Override
     public void migrateState(@NonNull PackageSetting oldPkgSetting,
             @NonNull PackageSetting newPkgSetting) {
-        String pkgName = newPkgSetting.getName();
+        String pkgName = newPkgSetting.getPackageName();
         boolean sendBroadcast;
 
         synchronized (mLock) {
@@ -936,7 +936,7 @@
         //  gains or loses all domains.
 
         UUID domainSetId = newPkgSetting.getDomainSetId();
-        String pkgName = newPkgSetting.getName();
+        String pkgName = newPkgSetting.getPackageName();
 
         boolean sendBroadcast = true;
 
@@ -1032,7 +1032,7 @@
             @NonNull ArrayMap<String, Integer> stateMap,
             @NonNull ArraySet<String> autoVerifyDomains) {
         if (pkgSetting.isSystem()
-                && mSystemConfig.getLinkedApps().contains(pkgSetting.getName())) {
+                && mSystemConfig.getLinkedApps().contains(pkgSetting.getPackageName())) {
             int domainsSize = autoVerifyDomains.size();
             for (int index = 0; index < domainsSize; index++) {
                 stateMap.put(autoVerifyDomains.valueAt(index),
@@ -1718,7 +1718,7 @@
     @Override
     public int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
             @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
-        String packageName = pkgSetting.getName();
+        String packageName = pkgSetting.getPackageName();
         if (!DomainVerificationUtils.isDomainVerificationIntent(intent, resolveInfoFlags)) {
             if (DEBUG_APPROVAL) {
                 debugApproval(packageName, intent, userId, false, "not valid intent");
@@ -1762,7 +1762,7 @@
     private int approvalLevelForDomainInternal(@NonNull PackageSetting pkgSetting,
             @NonNull String host, boolean includeNegative, @UserIdInt int userId,
             @NonNull Object debugObject) {
-        String packageName = pkgSetting.getName();
+        String packageName = pkgSetting.getPackageName();
         final AndroidPackage pkg = pkgSetting.getPkg();
 
         if (pkg != null && includeNegative && !mCollector.containsWebDomain(pkg, host)) {
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index edd5f5f..27a16e9 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -41,6 +41,7 @@
 import com.android.server.devicestate.DeviceStateProvider;
 import com.android.server.policy.devicestate.config.Conditions;
 import com.android.server.policy.devicestate.config.DeviceStateConfig;
+import com.android.server.policy.devicestate.config.Flags;
 import com.android.server.policy.devicestate.config.LidSwitchCondition;
 import com.android.server.policy.devicestate.config.NumericRange;
 import com.android.server.policy.devicestate.config.SensorCondition;
@@ -81,13 +82,14 @@
 public final class DeviceStateProviderImpl implements DeviceStateProvider,
         InputManagerInternal.LidSwitchCallback, SensorEventListener {
     private static final String TAG = "DeviceStateProviderImpl";
+    private static final boolean DEBUG = false;
 
     private static final BooleanSupplier TRUE_BOOLEAN_SUPPLIER = () -> true;
     private static final BooleanSupplier FALSE_BOOLEAN_SUPPLIER = () -> false;
 
     @VisibleForTesting
     static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(MINIMUM_DEVICE_STATE,
-            "DEFAULT");
+            "DEFAULT", 0 /* flags */);
 
     private static final String VENDOR_CONFIG_FILE_PATH = "etc/devicestate/";
     private static final String DATA_CONFIG_FILE_PATH = "system/devicestate/";
@@ -131,7 +133,26 @@
                         config.getDeviceState()) {
                     final int state = stateConfig.getIdentifier().intValue();
                     final String name = stateConfig.getName() == null ? "" : stateConfig.getName();
-                    deviceStateList.add(new DeviceState(state, name));
+
+                    int flags = 0;
+                    final Flags configFlags = stateConfig.getFlags();
+                    if (configFlags != null) {
+                        List<String> configFlagStrings = configFlags.getFlag();
+                        for (int i = 0; i < configFlagStrings.size(); i++) {
+                            final String configFlagString = configFlagStrings.get(i);
+                            switch (configFlagString) {
+                                case "FLAG_CANCEL_STICKY_REQUESTS":
+                                    flags |= DeviceState.FLAG_CANCEL_STICKY_REQUESTS;
+                                    break;
+                                default:
+                                    Slog.w(TAG, "Parsed unknown flag with name: "
+                                            + configFlagString);
+                                    break;
+                            }
+                        }
+                    }
+
+                    deviceStateList.add(new DeviceState(state, name, flags));
 
                     final Conditions condition = stateConfig.getConditions();
                     conditionsList.add(condition);
@@ -193,6 +214,10 @@
 
         for (int i = 0; i < stateConditions.size(); i++) {
             final int state = deviceStates.get(i).getIdentifier();
+            if (DEBUG) {
+                Slog.d(TAG, "Evaluating conditions for device state " + state
+                        + " (" + deviceStates.get(i).getName() + ")");
+            }
             final Conditions conditions = stateConditions.get(i);
             if (conditions == null) {
                 mStateConditions.put(state, TRUE_BOOLEAN_SUPPLIER);
@@ -213,6 +238,9 @@
             if (lidSwitchCondition != null) {
                 suppliers.add(new LidSwitchBooleanSupplier(lidSwitchCondition.getOpen()));
                 lidSwitchRequired = true;
+                if (DEBUG) {
+                    Slog.d(TAG, "Lid switch required");
+                }
             }
 
             List<SensorCondition> sensorConditions = conditions.getSensor();
@@ -229,6 +257,11 @@
                     break;
                 }
 
+                if (DEBUG) {
+                    Slog.d(TAG, "Found sensor with type: " + expectedSensorType
+                            + " (" + expectedSensorName + ")");
+                }
+
                 suppliers.add(new SensorBooleanSupplier(foundSensor, sensorCondition.getValue()));
                 sensorsRequired.add(foundSensor);
             }
@@ -323,6 +356,10 @@
             int newState = mOrderedStates[0].getIdentifier();
             for (int i = 0; i < mOrderedStates.length; i++) {
                 int state = mOrderedStates[i].getIdentifier();
+                if (DEBUG) {
+                    Slog.d(TAG, "Checking conditions for " + mOrderedStates[i].getName() + "("
+                            + i + ")");
+                }
                 boolean conditionSatisfied;
                 try {
                     conditionSatisfied = mStateConditions.get(state).getAsBoolean();
@@ -330,10 +367,16 @@
                     // Failed to compute the current state based on current available data. Return
                     // with the expectation that notifyDeviceStateChangedIfNeeded() will be called
                     // when a callback with the missing data is triggered.
+                    if (DEBUG) {
+                        Slog.d(TAG, "Unable to check current state", e);
+                    }
                     return;
                 }
 
                 if (conditionSatisfied) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Device State conditions satisfied, transition to " + state);
+                    }
                     newState = state;
                     break;
                 }
@@ -355,6 +398,9 @@
         synchronized (mLock) {
             mIsLidOpen = lidOpen;
         }
+        if (DEBUG) {
+            Slog.d(TAG, "Lid switch state: " + (lidOpen ? "open" : "closed"));
+        }
         notifyDeviceStateChangedIfNeeded();
     }
 
@@ -440,6 +486,9 @@
         private boolean adheresToRange(float value, @NonNull NumericRange range) {
             final BigDecimal min = range.getMin_optional();
             if (min != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "value: " + value + ", constraint min: " + min.floatValue());
+                }
                 if (value <= min.floatValue()) {
                     return false;
                 }
@@ -447,6 +496,10 @@
 
             final BigDecimal minInclusive = range.getMinInclusive_optional();
             if (minInclusive != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "value: " + value + ", constraint min-inclusive: "
+                            + minInclusive.floatValue());
+                }
                 if (value < minInclusive.floatValue()) {
                     return false;
                 }
@@ -454,6 +507,9 @@
 
             final BigDecimal max = range.getMax_optional();
             if (max != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "value: " + value + ", constraint max: " + max.floatValue());
+                }
                 if (value >= max.floatValue()) {
                     return false;
                 }
@@ -461,6 +517,10 @@
 
             final BigDecimal maxInclusive = range.getMaxInclusive_optional();
             if (maxInclusive != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "value: " + value + ", constraint max-inclusive: "
+                            + maxInclusive.floatValue());
+                }
                 if (value > maxInclusive.floatValue()) {
                     return false;
                 }
diff --git a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
index bdcd2cd..3524d7f 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
@@ -44,8 +44,8 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ScreenState {}
 
-    private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
-    private Long mLastChanged = null;
+    private volatile @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
+    private volatile Long mLastChanged = null;
 
     private static final int LOG_SUBTYPE_UNFOLDED = 0;
     private static final int LOG_SUBTYPE_FOLDED = 1;
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index a0771c0..e857d32 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -48,7 +48,7 @@
  * <li> Returning particular kind of application intent by special key.
  */
 class ModifierShortcutManager {
-    private static final String TAG = "ShortcutManager";
+    private static final String TAG = "WindowManager";
 
     private static final String TAG_BOOKMARKS = "bookmarks";
     private static final String TAG_BOOKMARK = "bookmark";
@@ -188,7 +188,7 @@
                                             | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                         } catch (PackageManager.NameNotFoundException e1) {
                             Log.w(TAG, "Unable to add bookmark: " + packageName
-                                    + "/" + className, e);
+                                    + "/" + className + " not found.");
                             continue;
                         }
                     }
@@ -213,10 +213,8 @@
                     mIntentShortcuts.put(shortcutChar, shortcut);
                 }
             }
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "Got exception parsing bookmarks.", e);
-        } catch (IOException e) {
-            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        } catch (XmlPullParserException | IOException e) {
+            Log.e(TAG, "Got exception parsing bookmarks.", e);
         }
     }
 
@@ -302,7 +300,7 @@
                     Slog.w(TAG, "Dropping application launch key because "
                             + "the activity to which it is registered was not found: "
                             + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
-                            + " category=" + category, ex);
+                            + " category=" + category);
                 }
                 return true;
             } else {
@@ -318,7 +316,7 @@
             } catch (ActivityNotFoundException ex) {
                 Slog.w(TAG, "Dropping shortcut key combination because "
                         + "the activity to which it is registered was not found: "
-                        + "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode), ex);
+                        + "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode));
             }
             return true;
         }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 2709d4f..ad43514 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -64,8 +64,8 @@
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.IntPair;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.PermissionThread;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -279,7 +279,7 @@
                 PermissionControllerManager manager = mPermControllerManagers.get(user);
                 if (manager == null) {
                     manager = new PermissionControllerManager(
-                            getUserContext(getContext(), user), PermissionThread.getHandler());
+                            getUserContext(getContext(), user), FgThread.getHandler());
                     mPermControllerManagers.put(user, manager);
                 }
                 manager.updateUserSensitiveForApp(uid);
@@ -287,9 +287,8 @@
         }, UserHandle.ALL, intentFilter, null, null);
 
         PermissionControllerManager manager = new PermissionControllerManager(
-                getUserContext(getContext(), Process.myUserHandle()),
-                PermissionThread.getHandler());
-        PermissionThread.getHandler().postDelayed(manager::updateUserSensitive,
+                getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler());
+        FgThread.getHandler().postDelayed(manager::updateUserSensitive,
                 USER_SENSITIVE_UPDATE_DELAY_MS);
     }
 
@@ -316,7 +315,7 @@
         if (isStarted(changedUserId)) {
             synchronized (mLock) {
                 if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
-                    PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                             PermissionPolicyService
                                     ::synchronizePackagePermissionsAndAppOpsForUser,
                             this, packageName, changedUserId));
@@ -422,9 +421,9 @@
             final PermissionControllerManager permissionControllerManager =
                     new PermissionControllerManager(
                             getUserContext(getContext(), UserHandle.of(userId)),
-                            PermissionThread.getHandler());
+                            FgThread.getHandler());
             permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
-                    PermissionThread.getExecutor(), successful -> {
+                    FgThread.getExecutor(), successful -> {
                         if (successful) {
                             future.complete(null);
                         } else {
@@ -528,7 +527,7 @@
             synchronized (mLock) {
                 if (!mIsUidSyncScheduled.get(uid)) {
                     mIsUidSyncScheduled.put(uid, true);
-                    PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                             PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
                             this, uid));
                 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 75b66b3..1a51394 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -485,6 +485,7 @@
     int mLidNavigationAccessibility;
     int mShortPressOnPowerBehavior;
     int mLongPressOnPowerBehavior;
+    long mLongPressOnPowerAssistantTimeoutMs;
     int mVeryLongPressOnPowerBehavior;
     int mDoublePressOnPowerBehavior;
     int mTriplePressOnPowerBehavior;
@@ -733,6 +734,9 @@
                     Settings.Global.POWER_BUTTON_LONG_PRESS), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POWER_BUTTON_VERY_LONG_PRESS), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
@@ -1741,6 +1745,8 @@
                 com.android.internal.R.integer.config_shortPressOnPowerBehavior);
         mLongPressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_longPressOnPowerBehavior);
+        mLongPressOnPowerAssistantTimeoutMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_longPressOnPowerDurationMs);
         mVeryLongPressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_veryLongPressOnPowerBehavior);
         mDoublePressOnPowerBehavior = mContext.getResources().getInteger(
@@ -1964,7 +1970,7 @@
      */
     private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
         PowerKeyRule(int gestures) {
-            super(KEYCODE_POWER, gestures);
+            super(mContext, KEYCODE_POWER, gestures);
         }
 
         @Override
@@ -1979,6 +1985,15 @@
         }
 
         @Override
+        long getLongPressTimeoutMs() {
+            if (getResolvedLongPressOnPowerBehavior() == LONG_PRESS_POWER_ASSISTANT) {
+                return mLongPressOnPowerAssistantTimeoutMs;
+            } else {
+                return super.getLongPressTimeoutMs();
+            }
+        }
+
+        @Override
         void onLongPress(long eventTime) {
             if (mSingleKeyGestureDetector.beganFromNonInteractive()
                     && !mSupportLongPressPowerWhenNonInteractive) {
@@ -2006,7 +2021,7 @@
      */
     private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
         BackKeyRule(int gestures) {
-            super(KEYCODE_BACK, gestures);
+            super(mContext, KEYCODE_BACK, gestures);
         }
 
         @Override
@@ -2026,7 +2041,7 @@
     }
 
     private void initSingleKeyGestureRules() {
-        mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext);
+        mSingleKeyGestureDetector = new SingleKeyGestureDetector();
 
         int powerKeyGestures = 0;
         if (hasVeryLongPressOnPowerBehavior()) {
@@ -2124,6 +2139,11 @@
                     Settings.Global.POWER_BUTTON_LONG_PRESS,
                     mContext.getResources().getInteger(
                             com.android.internal.R.integer.config_longPressOnPowerBehavior));
+            mLongPressOnPowerAssistantTimeoutMs = Settings.Global.getLong(
+                    mContext.getContentResolver(),
+                    Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS,
+                    mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_longPressOnPowerDurationMs));
             mVeryLongPressOnPowerBehavior = Settings.Global.getInt(resolver,
                     Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
                     mContext.getResources().getInteger(
@@ -2798,9 +2818,11 @@
                         mInputManagerInternal.toggleCapsLock(event.getDeviceId());
                         mPendingCapsLockToggle = false;
                     } else if (mPendingMetaAction) {
-                        launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
-                                event.getDeviceId(),
-                                event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
+                        if (!canceled) {
+                            launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
+                                    event.getDeviceId(),
+                                    event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
+                        }
                         mPendingMetaAction = false;
                     }
                 }
@@ -5340,6 +5362,9 @@
                 pw.print("mLongPressOnPowerBehavior=");
                 pw.println(longPressOnPowerBehaviorToString(mLongPressOnPowerBehavior));
         pw.print(prefix);
+        pw.print("mLongPressOnPowerAssistantTimeoutMs=");
+        pw.println(mLongPressOnPowerAssistantTimeoutMs);
+        pw.print(prefix);
                 pw.print("mVeryLongPressOnPowerBehavior=");
                 pw.println(veryLongPressOnPowerBehaviorToString(mVeryLongPressOnPowerBehavior));
         pw.print(prefix);
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index 1ef2bf9..6fee69b 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -44,9 +44,6 @@
     private static final int MSG_KEY_VERY_LONG_PRESS = 1;
     private static final int MSG_KEY_DELAYED_PRESS = 2;
 
-    private final long mLongPressTimeout;
-    private final long mVeryLongPressTimeout;
-
     private volatile int mKeyPressCounter;
     private boolean mBeganFromNonInteractive = false;
 
@@ -86,12 +83,19 @@
      *  </pre>
      */
     abstract static class SingleKeyRule {
+
         private final int mKeyCode;
         private final int mSupportedGestures;
+        private final long mDefaultLongPressTimeout;
+        private final long mDefaultVeryLongPressTimeout;
 
-        SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) {
+        SingleKeyRule(Context context, int keyCode, @KeyGestureFlag int supportedGestures) {
             mKeyCode = keyCode;
             mSupportedGestures = supportedGestures;
+            mDefaultLongPressTimeout =
+                ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
+            mDefaultVeryLongPressTimeout = context.getResources().getInteger(
+                com.android.internal.R.integer.config_veryLongPressTimeout);
         }
 
         /**
@@ -134,10 +138,28 @@
          */
         void onMultiPress(long downTime, int count) {}
         /**
+         *  Returns the timeout in milliseconds for a long press.
+         *
+         *  If multipress is also supported, this should always be greater than the multipress
+         *  timeout. If very long press is supported, this should always be less than the very long
+         *  press timeout.
+         */
+        long getLongPressTimeoutMs() {
+            return mDefaultLongPressTimeout;
+        }
+        /**
          *  Callback when long press has been detected.
          */
         void onLongPress(long eventTime) {}
         /**
+         *  Returns the timeout in milliseconds for a very long press.
+         *
+         *  If long press is supported, this should always be longer than the long press timeout.
+         */
+        long getVeryLongPressTimeoutMs() {
+            return mDefaultVeryLongPressTimeout;
+        }
+        /**
          *  Callback when very long press has been detected.
          */
         void onVeryLongPress(long eventTime) {}
@@ -151,10 +173,7 @@
         }
     }
 
-    public SingleKeyGestureDetector(Context context) {
-        mLongPressTimeout = ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
-        mVeryLongPressTimeout = context.getResources().getInteger(
-                com.android.internal.R.integer.config_veryLongPressTimeout);
+    public SingleKeyGestureDetector() {
         mHandler = new KeyHandler();
     }
 
@@ -225,14 +244,14 @@
                 final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0,
                         eventTime);
                 msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, mLongPressTimeout);
+                mHandler.sendMessageDelayed(msg, mActiveRule.getLongPressTimeoutMs());
             }
 
             if (mActiveRule.supportVeryLongPress()) {
                 final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0,
                         eventTime);
                 msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, mVeryLongPressTimeout);
+                mHandler.sendMessageDelayed(msg, mActiveRule.getVeryLongPressTimeoutMs());
             }
         } else {
             mHandler.removeMessages(MSG_KEY_LONG_PRESS);
diff --git a/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
index 3d47e92..0bfb55c 100644
--- a/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
+++ b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
@@ -34,7 +34,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.PackageUtils;
 import android.util.Slog;
 import android.util.Xml;
 
@@ -43,15 +42,18 @@
 import com.android.server.LocalServices;
 import com.android.server.role.RoleServicePlatformHelper;
 
+import libcore.util.HexEncoding;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -300,45 +302,88 @@
     public String computePackageStateHash(@UserIdInt int userId) {
         PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
+        final MessageDigestUtils md = new MessageDigestUtils();
+
         packageManagerInternal.forEachInstalledPackage(pkg -> {
-            try {
-                dataOutputStream.writeUTF(pkg.getPackageName());
-                dataOutputStream.writeLong(pkg.getLongVersionCode());
-                dataOutputStream.writeInt(packageManagerInternal.getApplicationEnabledState(
-                        pkg.getPackageName(), userId));
+            md.writeString(pkg.getPackageName());
+            md.writeLong(pkg.getLongVersionCode());
+            md.writeInt(packageManagerInternal.getApplicationEnabledState(pkg.getPackageName(),
+                    userId));
 
-                final List<String> requestedPermissions = pkg.getRequestedPermissions();
-                final int requestedPermissionsSize = requestedPermissions.size();
-                dataOutputStream.writeInt(requestedPermissionsSize);
-                for (int i = 0; i < requestedPermissionsSize; i++) {
-                    dataOutputStream.writeUTF(requestedPermissions.get(i));
-                }
+            final List<String> requestedPermissions = pkg.getRequestedPermissions();
+            final int requestedPermissionsSize = requestedPermissions.size();
+            md.writeInt(requestedPermissionsSize);
+            for (int i = 0; i < requestedPermissionsSize; i++) {
+                md.writeString(requestedPermissions.get(i));
+            }
 
-                final ArraySet<String> enabledComponents =
-                        packageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId);
-                final int enabledComponentsSize = CollectionUtils.size(enabledComponents);
-                dataOutputStream.writeInt(enabledComponentsSize);
-                for (int i = 0; i < enabledComponentsSize; i++) {
-                    dataOutputStream.writeUTF(enabledComponents.valueAt(i));
-                }
+            final ArraySet<String> enabledComponents = packageManagerInternal.getEnabledComponents(
+                    pkg.getPackageName(), userId);
+            final int enabledComponentsSize = CollectionUtils.size(enabledComponents);
+            md.writeInt(enabledComponentsSize);
+            for (int i = 0; i < enabledComponentsSize; i++) {
+                md.writeString(enabledComponents.valueAt(i));
+            }
 
-                final ArraySet<String> disabledComponents =
-                        packageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId);
-                final int disabledComponentsSize = CollectionUtils.size(disabledComponents);
-                for (int i = 0; i < disabledComponentsSize; i++) {
-                    dataOutputStream.writeUTF(disabledComponents.valueAt(i));
-                }
+            final ArraySet<String> disabledComponents =
+                    packageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId);
+            final int disabledComponentsSize = CollectionUtils.size(disabledComponents);
+            for (int i = 0; i < disabledComponentsSize; i++) {
+                md.writeString(disabledComponents.valueAt(i));
+            }
 
-                for (final Signature signature : pkg.getSigningDetails().getSignatures()) {
-                    dataOutputStream.write(signature.toByteArray());
-                }
-            } catch (IOException e) {
-                // Never happens for ByteArrayOutputStream and DataOutputStream.
-                throw new AssertionError(e);
+            for (final Signature signature : pkg.getSigningDetails().getSignatures()) {
+                md.writeBytes(signature.toByteArray());
             }
         }, userId);
-        return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray());
+
+        return md.getDigestAsString();
+    }
+
+    private static class MessageDigestUtils {
+        private final byte[] mBuffer = new byte[8];
+        private final MessageDigest mMessageDigest;
+
+        MessageDigestUtils() {
+            try {
+                mMessageDigest = MessageDigest.getInstance("SHA256");
+            } catch (NoSuchAlgorithmException e) {
+                /* can't happen */
+                throw new RuntimeException("Failed to create MessageDigest", e);
+            }
+        }
+
+        @NonNull
+        String getDigestAsString() {
+            return HexEncoding.encodeToString(mMessageDigest.digest(), true /* uppercase */);
+        }
+
+        void writeBytes(@NonNull byte[] bytes) {
+            mMessageDigest.update(bytes);
+        }
+
+        void writeString(@NonNull String s) {
+            mMessageDigest.update(s.getBytes(StandardCharsets.UTF_8));
+        }
+
+        void writeLong(long v) {
+            mBuffer[0] = (byte) (v >>> 56);
+            mBuffer[1] = (byte) (v >>> 48);
+            mBuffer[2] = (byte) (v >>> 40);
+            mBuffer[3] = (byte) (v >>> 32);
+            mBuffer[4] = (byte) (v >>> 24);
+            mBuffer[5] = (byte) (v >>> 16);
+            mBuffer[6] = (byte) (v >>>  8);
+            mBuffer[7] = (byte) (v >>>  0);
+            mMessageDigest.update(mBuffer, 0, 8);
+        }
+
+        void writeInt(int v) {
+            mBuffer[0] = (byte) (v >>> 24);
+            mBuffer[1] = (byte) (v >>> 16);
+            mBuffer[2] = (byte) (v >>>  8);
+            mBuffer[3] = (byte) (v >>>  0);
+            mMessageDigest.update(mBuffer, 0, 4);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 218ab78..9e61dce 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -129,6 +129,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 
 /**
@@ -539,6 +540,11 @@
     // True if the proximity sensor reads a positive result.
     private boolean mProximityPositive;
 
+    // Indicates that we have already intercepted the power key to temporarily ignore the proximity
+    // wake lock and turn the screen back on. This should get reset when prox reads 'far' again
+    // (when {@link #mProximityPositive} is set to false).
+    private boolean mInterceptedPowerKeyForProximity;
+
     // Screen brightness setting limits.
     public final float mScreenBrightnessMinimum;
     public final float mScreenBrightnessMaximum;
@@ -1506,7 +1512,11 @@
                 mRequestWaitForNegativeProximity = true;
             }
 
-            wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+            try {
+                wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+            } catch (NoSuchElementException e) {
+                Slog.wtf(TAG, "Failed to unlink wakelock", e);
+            }
             removeWakeLockLocked(wakeLock, index);
         }
     }
@@ -3330,6 +3340,7 @@
         public void onProximityNegative() {
             synchronized (mLock) {
                 mProximityPositive = false;
+                mInterceptedPowerKeyForProximity = false;
                 mDirty |= DIRTY_PROXIMITY_POSITIVE;
                 userActivityNoUpdateLocked(Display.DEFAULT_DISPLAY_GROUP, mClock.uptimeMillis(),
                         PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
@@ -4107,7 +4118,10 @@
         if (sQuiescent) {
             // Pass the optional "quiescent" argument to the bootloader to let it know
             // that it should not turn the screen/lights on.
-            reason = reason + ",quiescent";
+            if (reason != ""){
+                reason += ",";
+            }
+            reason = reason + "quiescent";
         }
 
         SystemProperties.set("sys.powerctl", "reboot," + reason);
@@ -4178,6 +4192,8 @@
             }
             pw.println();
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
+            pw.println("  mInterceptedPowerKeyForProximity="
+                    + mInterceptedPowerKeyForProximity);
             pw.println("  mSandmanScheduled=" + mSandmanScheduled);
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
@@ -6009,8 +6025,9 @@
             final DisplayPowerRequest displayPowerRequest =
                     mDisplayGroupPowerStateMapper.getPowerRequestLocked(
                             Display.DEFAULT_DISPLAY_GROUP);
-            if (displayPowerRequest.useProximitySensor && mProximityPositive) {
+            if (mProximityPositive && !mInterceptedPowerKeyForProximity) {
                 mDisplayManagerInternal.ignoreProximitySensorUntilChanged();
+                mInterceptedPowerKeyForProximity = true;
                 return true;
             }
         }
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/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 2a95416..06253a0 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -124,12 +124,8 @@
         @Override
         public void read(InputStream in) throws IOException {
             while (in.available() > 0) {
-                try {
-                    DataElement dataElement = new DataElement(in);
-                    mCallback.onReadDataElement(dataElement.getData());
-                } catch (IOException e) {
-                    Slog.e(TAG, "Failed to read from storage. " + e.getMessage());
-                }
+                DataElement dataElement = new DataElement(in);
+                mCallback.onReadDataElement(dataElement.getData());
             }
         }
     }
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/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index e006b65..47bd72a 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -21,6 +21,10 @@
 import android.hardware.audio.common.V2_0.Uuid;
 import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
 import android.hardware.soundtrigger.V2_3.ISoundTriggerHw;
+import android.media.audio.common.AidlConversion;
+import android.media.audio.common.AudioConfig;
+import android.media.audio.common.AudioConfigBase;
+import android.media.audio.common.AudioOffloadInfo;
 import android.media.soundtrigger.AudioCapabilities;
 import android.media.soundtrigger.ConfidenceLevel;
 import android.media.soundtrigger.ModelParameter;
@@ -36,8 +40,6 @@
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.SoundModelType;
-import android.media.audio.common.AudioConfig;
-import android.media.audio.common.AudioOffloadInfo;
 import android.os.HidlMemory;
 import android.os.HidlMemoryUtil;
 import android.os.ParcelFileDescriptor;
@@ -303,7 +305,7 @@
         aidlEvent.captureDelayMs = hidlEvent.captureDelayMs;
         aidlEvent.capturePreambleMs = hidlEvent.capturePreambleMs;
         aidlEvent.triggerInData = hidlEvent.triggerInData;
-        aidlEvent.audioConfig = hidl2aidlAudioConfig(hidlEvent.audioConfig);
+        aidlEvent.audioConfig = hidl2aidlAudioConfig(hidlEvent.audioConfig, true /*isInput*/);
         aidlEvent.data = new byte[hidlEvent.data.size()];
         for (int i = 0; i < aidlEvent.data.length; ++i) {
             aidlEvent.data[i] = hidlEvent.data.get(i);
@@ -348,13 +350,10 @@
 
     static @NonNull
     AudioConfig hidl2aidlAudioConfig(
-            @NonNull android.hardware.audio.common.V2_0.AudioConfig hidlConfig) {
+            @NonNull android.hardware.audio.common.V2_0.AudioConfig hidlConfig, boolean isInput) {
         AudioConfig aidlConfig = new AudioConfig();
-        // TODO(ytai): channelMask and format might need a more careful conversion to make sure the
-        //  constants match.
-        aidlConfig.sampleRateHz = hidlConfig.sampleRateHz;
-        aidlConfig.channelMask = hidlConfig.channelMask;
-        aidlConfig.format = hidlConfig.format;
+        aidlConfig.base = hidl2aidlAudioConfigBase(hidlConfig.sampleRateHz, hidlConfig.channelMask,
+                hidlConfig.format, isInput);
         aidlConfig.offloadInfo = hidl2aidlOffloadInfo(hidlConfig.offloadInfo);
         aidlConfig.frameCount = hidlConfig.frameCount;
         return aidlConfig;
@@ -364,22 +363,36 @@
     AudioOffloadInfo hidl2aidlOffloadInfo(
             @NonNull android.hardware.audio.common.V2_0.AudioOffloadInfo hidlInfo) {
         AudioOffloadInfo aidlInfo = new AudioOffloadInfo();
-        // TODO(ytai): channelMask, format, streamType and usage might need a more careful
-        //  conversion to make sure the constants match.
-        aidlInfo.sampleRateHz = hidlInfo.sampleRateHz;
-        aidlInfo.channelMask = hidlInfo.channelMask;
-        aidlInfo.format = hidlInfo.format;
-        aidlInfo.streamType = hidlInfo.streamType;
+        aidlInfo.base = hidl2aidlAudioConfigBase(hidlInfo.sampleRateHz, hidlInfo.channelMask,
+                hidlInfo.format, false /*isInput*/);
+        aidlInfo.streamType = AidlConversion.legacy2aidl_audio_stream_type_t_AudioStreamType(
+                hidlInfo.streamType);
         aidlInfo.bitRatePerSecond = hidlInfo.bitRatePerSecond;
-        aidlInfo.durationMicroseconds = hidlInfo.durationMicroseconds;
+        aidlInfo.durationUs = hidlInfo.durationMicroseconds;
         aidlInfo.hasVideo = hidlInfo.hasVideo;
         aidlInfo.isStreaming = hidlInfo.isStreaming;
         aidlInfo.bitWidth = hidlInfo.bitWidth;
-        aidlInfo.bufferSize = hidlInfo.bufferSize;
-        aidlInfo.usage = hidlInfo.usage;
+        aidlInfo.offloadBufferSize = hidlInfo.bufferSize;
+        aidlInfo.usage = AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(hidlInfo.usage);
         return aidlInfo;
     }
 
+    // Ideally we would want to convert AudioConfigBase as a unit, however
+    // HIDL V2 lacks this type, so convert by field instead.
+    static @NonNull
+    AudioConfigBase hidl2aidlAudioConfigBase(int sampleRateHz, int channelMask, int format,
+            boolean isInput) {
+        AudioConfigBase aidlBase = new AudioConfigBase();
+        aidlBase.sampleRate = sampleRateHz;
+        // Relies on the fact that HIDL AudioChannelMask uses the same constant values as
+        // system/audio.h.
+        aidlBase.channelMask = AidlConversion.legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                channelMask, isInput);
+        // Relies on the fact that HIDL AudioFormat uses the same constant values as system/audio.h.
+        aidlBase.format = AidlConversion.legacy2aidl_audio_format_t_AudioFormatDescription(format);
+        return aidlBase;
+    }
+
     @Nullable
     static ModelParameterRange hidl2aidlModelParameterRange(
             android.hardware.soundtrigger.V2_3.ModelParameterRange hidlRange) {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index 7a1f775..c638201 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -60,7 +60,6 @@
     private @Nullable android.hardware.soundtrigger.V2_1.ISoundTriggerHw mUnderlying_2_1;
     private @Nullable android.hardware.soundtrigger.V2_2.ISoundTriggerHw mUnderlying_2_2;
     private @Nullable android.hardware.soundtrigger.V2_3.ISoundTriggerHw mUnderlying_2_3;
-    private @Nullable android.hardware.soundtrigger.V2_4.ISoundTriggerHw mUnderlying_2_4;
 
     // HAL <=2.1 requires us to pass a callback argument to startRecognition. We will store the one
     // passed on load and then pass it on start. We don't bother storing the callback on newer
@@ -89,13 +88,10 @@
             ICaptureStateNotifier notifier) {
         SoundTriggerHw2Compat compat = new SoundTriggerHw2Compat(binder, rebootRunnable);
         ISoundTriggerHal result = compat;
-        // Add max model limiter for versions <2.4.
-        if (compat.mUnderlying_2_4 == null) {
-            result = new SoundTriggerHalMaxModelLimiter(result,
-                    compat.mProperties.maxSoundModels);
-        }
-        // Add concurrent capture handler for versions <2.4 which do not support concurrent capture.
-        if (compat.mUnderlying_2_4 == null && !compat.mProperties.concurrentCapture) {
+        // Add max model limiter for versions.
+        result = new SoundTriggerHalMaxModelLimiter(result, compat.mProperties.maxSoundModels);
+        // Add concurrent capture handler for HALs which do not support concurrent capture.
+        if (!compat.mProperties.concurrentCapture) {
             result = new SoundTriggerHalConcurrentCaptureHandler(result, notifier);
         }
         return result;
@@ -113,21 +109,11 @@
         // version, so we go down the versions in descending order to find the latest one supported,
         // and then simply up-cast it to obtain all the versions that are earlier.
 
-        // Attempt 2.4
-        android.hardware.soundtrigger.V2_4.ISoundTriggerHw as2_4 =
-                android.hardware.soundtrigger.V2_4.ISoundTriggerHw.asInterface(binder);
-        if (as2_4 != null) {
-            mUnderlying_2_0 =
-                    mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = as2_4;
-            return;
-        }
-
         // Attempt 2.3
         android.hardware.soundtrigger.V2_3.ISoundTriggerHw as2_3 =
                 android.hardware.soundtrigger.V2_3.ISoundTriggerHw.asInterface(binder);
         if (as2_3 != null) {
             mUnderlying_2_0 = mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = as2_3;
-            mUnderlying_2_4 = null;
             return;
         }
 
@@ -136,7 +122,7 @@
                 android.hardware.soundtrigger.V2_2.ISoundTriggerHw.asInterface(binder);
         if (as2_2 != null) {
             mUnderlying_2_0 = mUnderlying_2_1 = mUnderlying_2_2 = as2_2;
-            mUnderlying_2_3 = mUnderlying_2_4 = null;
+            mUnderlying_2_3 = null;
             return;
         }
 
@@ -145,7 +131,7 @@
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHw.asInterface(binder);
         if (as2_1 != null) {
             mUnderlying_2_0 = mUnderlying_2_1 = as2_1;
-            mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = null;
+            mUnderlying_2_2 = mUnderlying_2_3 = null;
             return;
         }
 
@@ -154,7 +140,7 @@
                 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.asInterface(binder);
         if (as2_0 != null) {
             mUnderlying_2_0 = as2_0;
-            mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = null;
+            mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = null;
             return;
         }
 
@@ -213,16 +199,8 @@
 
     @Override
     public void registerCallback(GlobalCallback callback) {
-        try {
-            try {
-                as2_4().registerGlobalCallback(new GlobalCallbackWrapper(callback));
-            } catch (NotSupported e) {
-                // In versions < 2.4 the events represented by this callback don't exist, we can
-                // safely ignore this.
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
+        // In versions 2.x the events represented by this callback don't exist, we can
+        // safely ignore this.
     }
 
     @Override
@@ -232,29 +210,18 @@
         try {
             AtomicInteger retval = new AtomicInteger(-1);
             AtomicInteger handle = new AtomicInteger(0);
-
             try {
-                as2_4().loadSoundModel_2_4(hidlModel, new ModelCallbackWrapper(callback),
+                as2_1().loadSoundModel_2_1(hidlModel, new ModelCallbackWrapper(callback),
+                        0,
                         (r, h) -> {
                             retval.set(r);
                             handle.set(h);
                         });
-                handleHalStatusAllowBusy(retval.get(), "loadSoundModel_2_4");
-            } catch (NotSupported e) {
-                // Fall-back to the 2.1 version:
-                try {
-                    as2_1().loadSoundModel_2_1(hidlModel, new ModelCallbackWrapper(callback),
-                            0,
-                            (r, h) -> {
-                                retval.set(r);
-                                handle.set(h);
-                            });
-                    handleHalStatus(retval.get(), "loadSoundModel_2_1");
-                    mModelCallbacks.put(handle.get(), callback);
-                } catch (NotSupported ee) {
-                    // Fall-back to the 2.0 version:
-                    return loadSoundModel_2_0(hidlModel, callback);
-                }
+                handleHalStatus(retval.get(), "loadSoundModel_2_1");
+                mModelCallbacks.put(handle.get(), callback);
+            } catch (NotSupported ee) {
+                // Fall-back to the 2.0 version:
+                return loadSoundModel_2_0(hidlModel, callback);
             }
             return handle.get();
         } catch (RemoteException e) {
@@ -270,27 +237,17 @@
             AtomicInteger retval = new AtomicInteger(-1);
             AtomicInteger handle = new AtomicInteger(0);
             try {
-                as2_4().loadPhraseSoundModel_2_4(hidlModel, new ModelCallbackWrapper(callback),
+                as2_1().loadPhraseSoundModel_2_1(hidlModel, new ModelCallbackWrapper(callback),
+                        0,
                         (r, h) -> {
                             retval.set(r);
                             handle.set(h);
                         });
-                handleHalStatusAllowBusy(retval.get(), "loadPhraseSoundModel_2_4");
-            } catch (NotSupported e) {
-                // Fall-back to the 2.1 version:
-                try {
-                    as2_1().loadPhraseSoundModel_2_1(hidlModel, new ModelCallbackWrapper(callback),
-                            0,
-                            (r, h) -> {
-                                retval.set(r);
-                                handle.set(h);
-                            });
-                    handleHalStatus(retval.get(), "loadPhraseSoundModel_2_1");
-                    mModelCallbacks.put(handle.get(), callback);
-                } catch (NotSupported ee) {
-                    // Fall-back to the 2.0 version:
-                    return loadPhraseSoundModel_2_0(hidlModel, callback);
-                }
+                handleHalStatus(retval.get(), "loadPhraseSoundModel_2_1");
+                mModelCallbacks.put(handle.get(), callback);
+            } catch (NotSupported ee) {
+                // Fall-back to the 2.0 version:
+                return loadPhraseSoundModel_2_0(hidlModel, callback);
             }
             return handle.get();
         } catch (RemoteException e) {
@@ -328,17 +285,11 @@
                 ConversionUtil.aidl2hidlRecognitionConfig(config, deviceHandle, ioHandle);
         try {
             try {
-                int retval = as2_4().startRecognition_2_4(modelHandle, hidlConfig);
-                handleHalStatusAllowBusy(retval, "startRecognition_2_4");
-            } catch (NotSupported e) {
-                // Fall-back to the 2.3 version:
-                try {
-                    int retval = as2_3().startRecognition_2_3(modelHandle, hidlConfig);
-                    handleHalStatus(retval, "startRecognition_2_3");
-                } catch (NotSupported ee) {
-                    // Fall-back to the 2.0 version:
-                    startRecognition_2_1(modelHandle, hidlConfig);
-                }
+                int retval = as2_3().startRecognition_2_3(modelHandle, hidlConfig);
+                handleHalStatus(retval, "startRecognition_2_3");
+            } catch (NotSupported ee) {
+                // Fall-back to the 2.0 version:
+                startRecognition_2_1(modelHandle, hidlConfig);
             }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -551,14 +502,6 @@
         return mUnderlying_2_3;
     }
 
-    private @NonNull
-    android.hardware.soundtrigger.V2_4.ISoundTriggerHw as2_4() throws NotSupported {
-        if (mUnderlying_2_4 == null) {
-            throw new NotSupported("Underlying driver version < 2.4");
-        }
-        return mUnderlying_2_4;
-    }
-
     /**
      * A checked exception representing the requested interface version not being supported.
      * At the public interface layer, use {@link #throwAsRecoverableException()} to propagate it to
@@ -580,22 +523,8 @@
         }
     }
 
-    private static class GlobalCallbackWrapper extends
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback.Stub {
-        private final @NonNull GlobalCallback mDelegate;
-
-        private GlobalCallbackWrapper(@NonNull GlobalCallback delegate) {
-            mDelegate = delegate;
-        }
-
-        @Override
-        public void onResourcesAvailable() {
-            mDelegate.onResourcesAvailable();
-        }
-    }
-
     private static class ModelCallbackWrapper extends
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.Stub {
+            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.Stub {
         private final @NonNull ModelCallback mDelegate;
 
         private ModelCallbackWrapper(
@@ -604,11 +533,6 @@
         }
 
         @Override
-        public void modelUnloaded(int modelHandle) {
-            mDelegate.modelUnloaded(modelHandle);
-        }
-
-        @Override
         public void recognitionCallback_2_1(
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event,
                 int cookie) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index ff7e903..b58ca1f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -785,13 +785,14 @@
     @Override
     public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
             int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
-            int userId, String opPackageName, long operationId,
+            int userId, long operationId, String opPackageName, long requestId,
             @BiometricMultiSensorMode int multiSensorConfig) {
         enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed,
-                        requireConfirmation, userId, opPackageName, operationId, multiSensorConfig);
+                        requireConfirmation, userId, operationId, opPackageName, requestId,
+                        multiSensorConfig);
             } catch (RemoteException ex) {
             }
         }
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 83085cc..1ebb722 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -114,6 +114,8 @@
     private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
     private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>();
 
+    private final List<Message> mPendingTvinputInfoEvents = new LinkedList<>();
+
     // Calls to mListener should happen here.
     private final Handler mHandler = new ListenerHandler();
 
@@ -229,7 +231,16 @@
                             connection.getInputStateLocked(), 0, inputId).sendToTarget();
                     }
                 }
-            }
+            } else {
+                Message msg = mHandler.obtainMessage(ListenerHandler.TVINPUT_INFO_ADDED,
+                    deviceId, cableConnectionStatus, connection);
+                for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext();) {
+                    if (it.next().arg1 == deviceId) {
+                    it.remove();
+                    }
+                }
+                mPendingTvinputInfoEvents.add(msg);
+           }
             ITvInputHardwareCallback callback = connection.getCallbackLocked();
             if (callback != null) {
                 try {
@@ -288,6 +299,8 @@
             }
             mHardwareInputIdMap.put(deviceId, info.getId());
             mInputMap.put(info.getId(), info);
+            processPendingTvInputInfoEventsLocked();
+            Slog.d(TAG,"deviceId ="+ deviceId+", tvinputinfo = "+info);
 
             // Process pending state changes
 
@@ -530,6 +543,20 @@
         }
     }
 
+
+    private void processPendingTvInputInfoEventsLocked() {
+        for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext(); ) {
+            Message msg = it.next();
+            int deviceId =  msg.arg1;
+            String inputId = mHardwareInputIdMap.get(deviceId);
+            if (inputId != null) {
+                msg.sendToTarget();
+                it.remove();
+            }
+        }
+    }
+
+
     private void updateVolume() {
         mCurrentMaxIndex = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         mCurrentIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
@@ -1182,6 +1209,7 @@
         private static final int HDMI_DEVICE_ADDED = 4;
         private static final int HDMI_DEVICE_REMOVED = 5;
         private static final int HDMI_DEVICE_UPDATED = 6;
+        private static final int TVINPUT_INFO_ADDED = 7;
 
         @Override
         public final void handleMessage(Message msg) {
@@ -1226,6 +1254,29 @@
                     }
                     break;
                 }
+                case TVINPUT_INFO_ADDED: {
+                    int deviceId = msg.arg1;
+                    int cableConnectionStatus = msg.arg2;
+                    Connection connection =(Connection)msg.obj;
+
+                    int previousConfigsLength = connection.getConfigsLengthLocked();
+                    int previousCableConnectionStatus = connection.getInputStateLocked();
+                    String inputId = mHardwareInputIdMap.get(deviceId);
+
+                    if (inputId != null) {
+                        if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
+                            if (previousCableConnectionStatus != connection.getInputStateLocked()) {
+                                mListener.onStateChanged(inputId, connection.getInputStateLocked());
+                            }
+                        } else {
+                            if ((previousConfigsLength == 0)
+                                    != (connection.getConfigsLengthLocked() == 0)) {
+                                mListener.onStateChanged(inputId, connection.getInputStateLocked());
+                            }
+                        }
+                    }
+                    break;
+                }
                 default: {
                     Slog.w(TAG, "Unhandled message: " + msg);
                     break;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 36a854e..2894708 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2304,10 +2304,9 @@
         public void requestChannelBrowsable(Uri channelUri, int userId)
                 throws RemoteException {
             final String callingPackageName = getCallingPackageName();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, "requestChannelBrowsable");
             final long identity = Binder.clearCallingIdentity();
-            final int callingUid = Binder.getCallingUid();
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
-                userId, "requestChannelBrowsable");
             try {
                 Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
                 List<ResolveInfo> list = getContext().getPackageManager()
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..8fb81fa 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;
@@ -922,8 +922,10 @@
         }
         if (clientId == fe.getOwnerClientId()) {
             ClientProfile ownerClient = getClientProfile(fe.getOwnerClientId());
-            for (int shareOwnerId : ownerClient.getShareFeClientIds()) {
-                clearFrontendAndClientMapping(getClientProfile(shareOwnerId));
+            if (ownerClient != null) {
+                for (int shareOwnerId : ownerClient.getShareFeClientIds()) {
+                    clearFrontendAndClientMapping(getClientProfile(shareOwnerId));
+                }
             }
         }
         clearFrontendAndClientMapping(getClientProfile(clientId));
@@ -1039,20 +1041,13 @@
     @VisibleForTesting
     protected boolean reclaimResource(int reclaimingClientId,
             @TunerResourceManager.TunerResourceType int resourceType) {
-        if (DEBUG) {
-            Slog.d(TAG, "Reclaiming resources because higher priority client request resource type "
-                    + resourceType);
-        }
-        try {
-            mListeners.get(reclaimingClientId).getListener().onReclaimResources();
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingClientId, e);
-            return false;
-        }
 
         // Reclaim all the resources of the share owners of the frontend that is used by the current
         // resource reclaimed client.
         ClientProfile profile = getClientProfile(reclaimingClientId);
+        if (profile == null) {
+            return true;
+        }
         Set<Integer> shareFeClientIds = profile.getShareFeClientIds();
         for (int clientId : shareFeClientIds) {
             try {
@@ -1063,6 +1058,17 @@
             }
             clearAllResourcesAndClientMapping(getClientProfile(clientId));
         }
+
+        if (DEBUG) {
+            Slog.d(TAG, "Reclaiming resources because higher priority client request resource type "
+                    + resourceType + ", clientId:" + reclaimingClientId);
+        }
+        try {
+            mListeners.get(reclaimingClientId).getListener().onReclaimResources();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingClientId, e);
+            return false;
+        }
         clearAllResourcesAndClientMapping(profile);
         return true;
     }
@@ -1319,13 +1325,21 @@
     }
 
     private void clearFrontendAndClientMapping(ClientProfile profile) {
+        if (profile == null) {
+            return;
+        }
         for (Integer feId : profile.getInUseFrontendHandles()) {
             FrontendResource fe = getFrontendResource(feId);
-            if (fe.getOwnerClientId() == profile.getId()) {
+            int ownerClientId = fe.getOwnerClientId();
+            if (ownerClientId == profile.getId()) {
                 fe.removeOwner();
                 continue;
             }
-            getClientProfile(fe.getOwnerClientId()).stopSharingFrontend(profile.getId());
+            ClientProfile ownerClientProfile = getClientProfile(ownerClientId);
+            if (ownerClientProfile != null) {
+                ownerClientProfile.stopSharingFrontend(profile.getId());
+            }
+
         }
         profile.releaseFrontend();
     }
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index fd1995d..b17257a 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -706,10 +706,10 @@
                                         sourcePkg, targetPkg, targetUid, grantUri);
                                 perm.initPersistedModes(modeFlags, createdTime);
                                 mPmInternal.grantImplicitAccess(
-                                        targetUserId, null,
+                                        targetUserId, null /* intent */,
                                         UserHandle.getAppId(targetUid),
                                         pi.applicationInfo.uid,
-                                        false /* direct */);
+                                        false /* direct */, true /* retainOnUpdate */);
                             }
                         } else {
                             Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
@@ -773,8 +773,9 @@
             perm = findOrCreateUriPermissionLocked(pi.packageName, targetPkg, targetUid, grantUri);
         }
         perm.grantModes(modeFlags, owner);
-        mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null,
-                UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
+        mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null /*intent*/,
+                UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/,
+                (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0);
     }
 
     /** Like grantUriPermissionUnchecked, but takes an Intent. */
@@ -1187,7 +1188,7 @@
             // provider supports granting permissions
             mPmInternal.grantImplicitAccess(
                     UserHandle.getUserId(targetUid), null,
-                    UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false);
+                    UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
             return -1;
         }
 
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index e447a23..4ae058d 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -33,6 +33,7 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.function.Function;
 
 /** Represents a vibration request to the vibrator service. */
@@ -58,6 +59,7 @@
         IGNORED_FOR_ONGOING,
         IGNORED_FOR_POWER,
         IGNORED_FOR_SETTINGS,
+        IGNORED_SUPERSEDED,
     }
 
     /** Start time in CLOCK_BOOTTIME base. */
@@ -90,6 +92,9 @@
     private long mEndTimeDebug;
     private Status mStatus;
 
+    /** A {@link CountDownLatch} to enable waiting for completion. */
+    private final CountDownLatch mCompletionLatch = new CountDownLatch(1);
+
     Vibration(IBinder token, int id, CombinedVibration effect,
             VibrationAttributes attrs, int uid, String opPkg, String reason) {
         this.token = token;
@@ -118,6 +123,12 @@
         }
         mStatus = status;
         mEndTimeDebug = System.currentTimeMillis();
+        mCompletionLatch.countDown();
+    }
+
+    /** Waits indefinitely until another thread calls {@link #end(Status)} on this vibration. */
+    public void waitForEnd() throws InterruptedException {
+        mCompletionLatch.await();
     }
 
     /**
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index e85fa23..630bf0a 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -98,7 +98,7 @@
     }
 
     private final Object mLock = new Object();
-    private final WorkSource mWorkSource = new WorkSource();
+    private final WorkSource mWorkSource;
     private final PowerManager.WakeLock mWakeLock;
     private final IBatteryStats mBatteryStatsService;
     private final VibrationSettings mVibrationSettings;
@@ -119,9 +119,8 @@
         mVibrationSettings = vibrationSettings;
         mDeviceEffectAdapter = effectAdapter;
         mCallbacks = callbacks;
+        mWorkSource = new WorkSource(mVibration.uid);
         mWakeLock = wakeLock;
-        mWorkSource.set(vib.uid);
-        mWakeLock.setWorkSource(mWorkSource);
         mBatteryStatsService = batteryStatsService;
 
         CombinedVibration effect = vib.getEffect();
@@ -152,6 +151,7 @@
     @Override
     public void run() {
         Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+        mWakeLock.setWorkSource(mWorkSource);
         mWakeLock.acquire();
         try {
             mVibration.token.linkToDeath(this, 0);
@@ -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/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 69cc90bf..efccd57 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -304,7 +304,7 @@
         }
     }
 
-    /** Turns off the vibrator.This will affect the state of {@link #isVibrating()}. */
+    /** Turns off the vibrator. This will affect the state of {@link #isVibrating()}. */
     public void off() {
         synchronized (mLock) {
             mNativeWrapper.off();
@@ -313,6 +313,15 @@
         }
     }
 
+    /**
+     * Resets the vibrator hardware to a default state.
+     * This turns the vibrator off, which will affect the state of {@link #isVibrating()}.
+     */
+    public void reset() {
+        setExternalControl(false);
+        off();
+    }
+
     @Override
     public String toString() {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 2a47512..567463f 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -144,9 +144,12 @@
                     // them.  However it may happen that the system is currently playing
                     // haptic feedback as part of the transition.  So we don't cancel
                     // system vibrations.
+                    if (mNextVibration != null
+                            && !isSystemHapticFeedback(mNextVibration.getVibration())) {
+                        clearNextVibrationLocked(Vibration.Status.CANCELLED);
+                    }
                     if (mCurrentVibration != null
                             && !isSystemHapticFeedback(mCurrentVibration.getVibration())) {
-                        mNextVibration = null;
                         mCurrentVibration.cancel();
                     }
                 }
@@ -216,7 +219,7 @@
         // fresh boot.
         mNativeWrapper.cancelSynced();
         for (int i = 0; i < mVibrators.size(); i++) {
-            mVibrators.valueAt(i).off();
+            mVibrators.valueAt(i).reset();
         }
 
         IntentFilter filter = new IntentFilter();
@@ -336,17 +339,27 @@
     @Override // Binder call
     public void vibrate(int uid, String opPkg, @NonNull CombinedVibration effect,
             @Nullable VibrationAttributes attrs, String reason, IBinder token) {
+        vibrateInternal(uid, opPkg, effect, attrs, reason, token);
+    }
+
+    /**
+     * An internal-only version of vibrate that allows the caller access to the {@link Vibration}.
+     * The Vibration is only returned if it is ongoing after this method returns.
+     */
+    @Nullable
+    private Vibration vibrateInternal(int uid, String opPkg, @NonNull CombinedVibration effect,
+            @Nullable VibrationAttributes attrs, String reason, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
         try {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.VIBRATE, "vibrate");
 
             if (token == null) {
                 Slog.e(TAG, "token must not be null");
-                return;
+                return null;
             }
             enforceUpdateAppOpsStatsPermission(uid);
             if (!isEffectValid(effect)) {
-                return;
+                return null;
             }
             attrs = fixupVibrationAttributes(attrs);
             Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
@@ -357,13 +370,13 @@
                 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib);
                 if (ignoreStatus != null) {
                     endVibrationLocked(vib, ignoreStatus);
-                    return;
+                    return vib;
                 }
 
                 ignoreStatus = shouldIgnoreVibrationForCurrentLocked(vib);
                 if (ignoreStatus != null) {
                     endVibrationLocked(vib, ignoreStatus);
-                    return;
+                    return vib;
                 }
 
                 final long ident = Binder.clearCallingIdentity();
@@ -375,6 +388,7 @@
                     if (status != Vibration.Status.RUNNING) {
                         endVibrationLocked(vib, status);
                     }
+                    return vib;
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -401,7 +415,7 @@
                     if (mNextVibration != null
                             && shouldCancelVibration(mNextVibration.getVibration(),
                             usageFilter, token)) {
-                        mNextVibration = null;
+                        clearNextVibrationLocked(Vibration.Status.CANCELLED);
                     }
                     if (mCurrentVibration != null
                             && shouldCancelVibration(mCurrentVibration.getVibration(),
@@ -453,7 +467,8 @@
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback cb, ResultReceiver resultReceiver) {
-        new VibratorManagerShellCommand(this).exec(this, in, out, err, args, cb, resultReceiver);
+        new VibratorManagerShellCommand(cb.getShellCallbackBinder())
+                .exec(this, in, out, err, args, cb, resultReceiver);
     }
 
     @VisibleForTesting
@@ -521,7 +536,9 @@
             if (mCurrentVibration == null) {
                 return startVibrationThreadLocked(vibThread);
             }
-
+            // If there's already a vibration queued (waiting for the previous one to finish
+            // cancelling), end it cleanly and replace it with the new one.
+            clearNextVibrationLocked(Vibration.Status.IGNORED_SUPERSEDED);
             mNextVibration = vibThread;
             return Vibration.Status.RUNNING;
         } finally {
@@ -1300,6 +1317,14 @@
         }
     }
 
+    /** Clears mNextVibration if set, ending it cleanly */
+    private void clearNextVibrationLocked(Vibration.Status endStatus) {
+        if (mNextVibration != null) {
+            endVibrationLocked(mNextVibration.getVibration(), endStatus);
+            mNextVibration = null;
+        }
+    }
+
     /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */
     @VisibleForTesting
     final class ExternalVibratorService extends IExternalVibratorService.Stub {
@@ -1347,7 +1372,7 @@
                     // If we're not under external control right now, then cancel any normal
                     // vibration that may be playing and ready the vibrator for external control.
                     if (mCurrentVibration != null) {
-                        mNextVibration = null;
+                        clearNextVibrationLocked(Vibration.Status.IGNORED_FOR_EXTERNAL);
                         mCurrentVibration.cancelImmediately();
                         cancelingVibration = mCurrentVibration;
                     }
@@ -1355,8 +1380,8 @@
                     // At this point we have an externally controlled vibration playing already.
                     // Since the interface defines that only one externally controlled vibration can
                     // play at a time, we need to first mute the ongoing vibration and then return
-                    // a scale from this function for the new one. Ee can be assured that the
-                    // ongoing it will be muted in favor of the new vibration.
+                    // a scale from this function for the new one, so we can be assured that the
+                    // ongoing will be muted in favor of the new vibration.
                     //
                     // Note that this doesn't support multiple concurrent external controls, as we
                     // would need to mute the old one still if it came from a different controller.
@@ -1454,6 +1479,7 @@
         private final class CommonOptions {
             public boolean force = false;
             public String description = "Shell command";
+            public boolean background = false;
 
             CommonOptions() {
                 String nextArg;
@@ -1463,6 +1489,10 @@
                             getNextArgRequired(); // consume "-f"
                             force = true;
                             break;
+                        case "-B":
+                            getNextArgRequired(); // consume "-B"
+                            background = true;
+                            break;
                         case "-d":
                             getNextArgRequired(); // consume "-d"
                             description = getNextArgRequired();
@@ -1475,10 +1505,10 @@
             }
         }
 
-        private final IBinder mToken;
+        private final IBinder mShellCallbacksToken;
 
-        private VibratorManagerShellCommand(IBinder token) {
-            mToken = token;
+        private VibratorManagerShellCommand(IBinder shellCallbacksToken) {
+            mShellCallbacksToken = shellCallbacksToken;
         }
 
         @Override
@@ -1520,12 +1550,28 @@
             }
         }
 
-        private int runMono() {
-            CommonOptions commonOptions = new CommonOptions();
-            CombinedVibration effect = CombinedVibration.createParallel(nextEffect());
+        /**
+         * Runs a CombinedVibration using the configured common options and attributes.
+         */
+        private void runVibrate(CommonOptions commonOptions, CombinedVibration combined) {
             VibrationAttributes attrs = createVibrationAttributes(commonOptions);
-            vibrate(Binder.getCallingUid(), SHELL_PACKAGE_NAME, effect, attrs,
-                    commonOptions.description, mToken);
+            // If running in the background, bind to death of the server binder rather than the
+            // client, and the cancel command likewise uses the server binder reference to
+            // only cancel background vibrations.
+            IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
+                    : mShellCallbacksToken;
+            Vibration vib = vibrateInternal(Binder.getCallingUid(), SHELL_PACKAGE_NAME, combined,
+                    attrs, commonOptions.description, deathBinder);
+            if (vib != null && !commonOptions.background) {
+                try {
+                    vib.waitForEnd();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
+        private int runMono() {
+            runVibrate(new CommonOptions(), CombinedVibration.createParallel(nextEffect()));
             return 0;
         }
 
@@ -1537,9 +1583,7 @@
                 int vibratorId = Integer.parseInt(getNextArgRequired());
                 combination.addVibrator(vibratorId, nextEffect());
             }
-            VibrationAttributes attrs = createVibrationAttributes(commonOptions);
-            vibrate(Binder.getCallingUid(), SHELL_PACKAGE_NAME, combination.combine(), attrs,
-                    commonOptions.description, mToken);
+            runVibrate(commonOptions, combination.combine());
             return 0;
         }
 
@@ -1551,14 +1595,15 @@
                 int vibratorId = Integer.parseInt(getNextArgRequired());
                 combination.addNext(vibratorId, nextEffect());
             }
-            VibrationAttributes attrs = createVibrationAttributes(commonOptions);
-            vibrate(Binder.getCallingUid(), SHELL_PACKAGE_NAME, combination.combine(), attrs,
-                    commonOptions.description, mToken);
+            runVibrate(commonOptions, combination.combine());
             return 0;
         }
 
         private int runCancel() {
-            cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, mToken);
+            // Cancel is only needed if the vibration was run in the background, otherwise it's
+            // terminated by the shell command ending. In these cases, the token was that of the
+            // service rather than the client.
+            cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, VibratorManagerService.this);
             return 0;
         }
 
@@ -1741,7 +1786,7 @@
                 pw.println("    wait time in milliseconds.");
                 pw.println("    If -a is provided, the command accepts a second argument for ");
                 pw.println("    amplitude, in a scale of 1-255.");
-                pw.print("    waveform [-w delay] [-r index] [-a] [-f] [-c] ");
+                pw.print("  waveform [-w delay] [-r index] [-a] [-f] [-c] ");
                 pw.println("(<duration> [<amplitude>] [<frequency>])...");
                 pw.println("    Vibrates for durations and amplitudes in list; ignored when ");
                 pw.println("    device is on DND (Do Not Disturb) mode; touch feedback strength ");
@@ -1777,6 +1822,9 @@
                 pw.println("Common Options:");
                 pw.println("  -f");
                 pw.println("    Force. Ignore Do Not Disturb setting.");
+                pw.println("  -B");
+                pw.println("    Run in the background; without this option the shell cmd will");
+                pw.println("    block until the vibration has completed.");
                 pw.println("  -d <description>");
                 pw.println("    Add description to the vibration.");
                 pw.println("");
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index a713e5b..39d7a15 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -302,7 +302,8 @@
             builder.setUniqueId(UNIQUE_DISPLAY_ID);
             builder.setFlags(flags);
             mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
-                    builder.build(), null /* callback */, null /* handler */);
+                    builder.build(), null /* callback */, null /* handler */,
+                    null /* windowContext */);
 
             if (mVirtualDisplay != null) {
                 updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 2c56359..e48593c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wallpaper;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.app.WallpaperManager.COMMAND_REAPPLY;
 import static android.app.WallpaperManager.FLAG_LOCK;
 import static android.app.WallpaperManager.FLAG_SYSTEM;
@@ -2045,7 +2046,21 @@
         }
     }
 
+    private boolean hasCrossUserPermission() {
+        final int interactPermission =
+                mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL);
+        return interactPermission == PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
     public boolean hasNamedWallpaper(String name) {
+        final int callingUser = UserHandle.getCallingUserId();
+        final boolean allowCrossUser = hasCrossUserPermission();
+        if (DEBUG) {
+            Slog.d(TAG, "hasNamedWallpaper() caller " + Binder.getCallingUid()
+                    + " cross-user?: " + allowCrossUser);
+        }
+
         synchronized (mLock) {
             List<UserInfo> users;
             final long ident = Binder.clearCallingIdentity();
@@ -2055,6 +2070,11 @@
                 Binder.restoreCallingIdentity(ident);
             }
             for (UserInfo user: users) {
+                if (!allowCrossUser && callingUser != user.id) {
+                    // No cross-user information for callers without permission
+                    continue;
+                }
+
                 // ignore managed profiles
                 if (user.isManagedProfile()) {
                     continue;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 372d3ec..2b57179 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -35,6 +35,7 @@
 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PARAMS;
 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PKG;
 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_STACKS;
+import static com.android.server.accessibility.AccessibilityTraceProto.CPU_STATS;
 import static com.android.server.accessibility.AccessibilityTraceProto.ELAPSED_REALTIME_NANOS;
 import static com.android.server.accessibility.AccessibilityTraceProto.LOGGING_TYPE;
 import static com.android.server.accessibility.AccessibilityTraceProto.PROCESS_NAME;
@@ -75,6 +76,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TypedValue;
@@ -88,6 +90,7 @@
 import android.view.ViewConfiguration;
 import android.view.WindowInfo;
 import android.view.WindowManager;
+import android.view.WindowManagerPolicyConstants;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
@@ -667,6 +670,7 @@
             if (magnifying) {
                 switch (transition) {
                     case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN:
+                    case WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN:
                     case WindowManager.TRANSIT_OLD_TASK_OPEN:
                     case WindowManager.TRANSIT_OLD_TASK_TO_FRONT:
                     case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN:
@@ -1112,7 +1116,7 @@
                     final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
                     final int layer =
                             mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) *
-                                    WindowManagerService.TYPE_LAYER_MULTIPLIER;
+                                    WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
                     t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0);
                     InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t,
                             mDisplayContent.getDisplayId(), "Magnification Overlay");
@@ -1959,6 +1963,7 @@
             }
         }
 
+        private static final int CPU_STATS_COUNT = 5;
         private static final int BUFFER_CAPACITY = 1024 * 1024 * 12;
         private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace"
                 + WINSCOPE_EXT;
@@ -2230,6 +2235,7 @@
                                 mService.dumpDebugLocked(os, WindowTraceLogLevel.ALL);
                             }
                             os.end(tokenInner);
+                            os.write(CPU_STATS, printCpuStats(reportedTimeStampNanos));
 
                             os.end(tokenOuter);
                             synchronized (mLock) {
@@ -2262,5 +2268,15 @@
                 Slog.e(TAG, "Unable to write buffer to file", e);
             }
         }
+
+        /**
+         * Returns the string of CPU stats.
+         */
+        private String printCpuStats(long timeStampNanos) {
+            Pair<String, String> stats = mService.mAmInternal.getAppProfileStatsForDebugging(
+                    timeStampNanos, CPU_STATS_COUNT);
+
+            return stats.first + stats.second;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 331b8de..cc0db1d 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -21,6 +21,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.os.Process.INVALID_UID;
+import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -57,6 +59,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -68,6 +71,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.util.Slog;
 import android.view.RemoteAnimationDefinition;
@@ -79,6 +83,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.vr.VrManagerInternal;
 
@@ -549,7 +554,9 @@
                 if (ar == null) {
                     return null;
                 }
-                final ActivityRecord below = ar.getTask().getActivityBelow(ar);
+                // Exclude finishing activity.
+                final ActivityRecord below = ar.getTask().getActivity((r) -> !r.finishing,
+                        ar, false /*includeBoundary*/, true /*traverseTopToBottom*/);
                 if (below != null && below.getUid() == ar.getUid()) {
                     return below.appToken.asBinder();
                 }
@@ -583,20 +590,45 @@
 
     @Override
     public int getLaunchedFromUid(IBinder token) {
+        if (!canGetLaunchedFrom()) {
+            return INVALID_UID;
+        }
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-            return r != null ? r.launchedFromUid : android.os.Process.INVALID_UID;
+            return r != null ? r.launchedFromUid : INVALID_UID;
         }
     }
 
     @Override
     public String getLaunchedFromPackage(IBinder token) {
+        if (!canGetLaunchedFrom()) {
+            return null;
+        }
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
             return r != null ? r.launchedFromPackage : null;
         }
     }
 
+    /** Whether the caller can get the package or uid that launched its activity. */
+    private boolean canGetLaunchedFrom() {
+        final int uid = Binder.getCallingUid();
+        if (UserHandle.getAppId(uid) == SYSTEM_UID) {
+            return true;
+        }
+        final PackageManagerInternal pm = mService.mWindowManager.mPmInternal;
+        final AndroidPackage callingPkg = pm.getPackage(uid);
+        if (callingPkg == null) {
+            return false;
+        }
+        if (callingPkg.isSignedWithPlatformKey()) {
+            return true;
+        }
+        final String[] installerNames = pm.getKnownPackageNames(
+                PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.getUserId(uid));
+        return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]);
+    }
+
     @Override
     public void setRequestedOrientation(IBinder token, int requestedOrientation) {
         final long origId = Binder.clearCallingIdentity();
@@ -1197,10 +1229,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 20958aa..c715c39 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -59,6 +59,8 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
@@ -89,6 +91,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -157,6 +160,9 @@
     private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
     /** Map : Last launched activity => {@link TransitionInfo} */
     private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
+    /** SparseArray : Package UID => {@link PackageCompatStateInfo} */
+    private final SparseArray<PackageCompatStateInfo> mPackageUidToCompatStateInfo =
+            new SparseArray<>(0);
 
     private ArtManagerInternal mArtManagerInternal;
     private final StringBuilder mStringBuilder = new StringBuilder();
@@ -187,6 +193,10 @@
             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn();
         }
 
+        boolean hasActiveTransitionInfo() {
+            return mAssociatedTransitionInfo != null;
+        }
+
         boolean contains(ActivityRecord r) {
             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.contains(r);
         }
@@ -336,10 +346,11 @@
         }
 
         /** Only keep the records which can be drawn. */
-        void updatePendingDraw() {
+        void updatePendingDraw(boolean keepInitializing) {
             for (int i = mPendingDrawActivities.size() - 1; i >= 0; i--) {
                 final ActivityRecord r = mPendingDrawActivities.get(i);
-                if (!r.mVisibleRequested) {
+                if (!r.mVisibleRequested
+                        && !(keepInitializing && r.isState(ActivityRecord.State.INITIALIZING))) {
                     if (DEBUG_METRICS) Slog.i(TAG, "Discard pending draw " + r);
                     mPendingDrawActivities.remove(i);
                 }
@@ -447,6 +458,15 @@
         }
     }
 
+    /** Information about the App Compat state logging associated with a package UID . */
+    private static final class PackageCompatStateInfo {
+        /** All activities that have a visible state. */
+        final ArrayList<ActivityRecord> mVisibleActivities = new ArrayList<>();
+        /** The last logged state. */
+        int mLastLoggedState = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+        @Nullable ActivityRecord mLastLoggedActivity;
+    }
+
     ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper) {
         mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
         mSupervisor = supervisor;
@@ -663,7 +683,7 @@
         // visible such as after the top task is finished.
         for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
             final TransitionInfo prevInfo = mTransitionInfoList.get(i);
-            prevInfo.updatePendingDraw();
+            prevInfo.updatePendingDraw(false /* keepInitializing */);
             if (prevInfo.allDrawn()) {
                 abort(prevInfo, "nothing will be drawn");
             }
@@ -698,6 +718,7 @@
         // Always calculate the delay because the caller may need to know the individual drawn time.
         info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
         info.removePendingDrawActivity(r);
+        info.updatePendingDraw(false /* keepInitializing */);
         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
         if (info.mLoggedTransitionStarting && info.allDrawn()) {
             done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
@@ -749,7 +770,9 @@
             info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
             info.mReason = activityToReason.valueAt(index);
             info.mLoggedTransitionStarting = true;
-            info.updatePendingDraw();
+            // Do not remove activity in initializing state because the transition may be started
+            // by starting window. The initializing activity may be requested to visible soon.
+            info.updatePendingDraw(true /* keepInitializing */);
             if (info.allDrawn()) {
                 done(false /* abort */, info, "notifyTransitionStarting - all windows drawn",
                         timestampNs);
@@ -767,6 +790,21 @@
     /** Makes sure that the reference to the removed activity is cleared. */
     void notifyActivityRemoved(@NonNull ActivityRecord r) {
         mLastTransitionInfo.remove(r);
+
+        final int packageUid = r.info.applicationInfo.uid;
+        final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
+        if (compatStateInfo == null) {
+            return;
+        }
+
+        compatStateInfo.mVisibleActivities.remove(r);
+        if (compatStateInfo.mLastLoggedActivity == r) {
+            compatStateInfo.mLastLoggedActivity = null;
+        }
+        if (compatStateInfo.mVisibleActivities.isEmpty()) {
+            // No need to keep the entry if there are no visible activities.
+            mPackageUidToCompatStateInfo.remove(packageUid);
+        }
     }
 
     /**
@@ -1263,6 +1301,115 @@
                 memoryStat.swapInBytes);
     }
 
+    /**
+     * Logs the current App Compat state of the given {@link ActivityRecord} with its package
+     * UID, if all of the following hold:
+     * <ul>
+     *   <li>The current state is different than the last logged state for the package UID of the
+     *   activity.
+     *   <li>If the current state is NOT_VISIBLE, there is a previously logged state for the
+     *   package UID and there are no other visible activities with the same package UID.
+     *   <li>The last logged activity with the same package UID is either {@code activity} or the
+     *   last logged state is NOT_VISIBLE or NOT_LETTERBOXED.
+     * </ul>
+     *
+     * <p>If the current state is NOT_VISIBLE and the previous state which was logged by {@code
+     * activity} wasn't, looks for the first visible activity with the same package UID that has
+     * a letterboxed state, or a non-letterboxed state if there isn't one, and logs that state.
+     *
+     * <p>This method assumes that the caller is wrapping the call with a synchronized block so
+     * that there won't be a race condition between two activities with the same package.
+     */
+    void logAppCompatState(@NonNull ActivityRecord activity) {
+        final int packageUid = activity.info.applicationInfo.uid;
+        final int state = activity.getAppCompatState();
+
+        if (!mPackageUidToCompatStateInfo.contains(packageUid)) {
+            mPackageUidToCompatStateInfo.put(packageUid, new PackageCompatStateInfo());
+        }
+        final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
+        final int lastLoggedState = compatStateInfo.mLastLoggedState;
+        final ActivityRecord lastLoggedActivity = compatStateInfo.mLastLoggedActivity;
+
+        final boolean isVisible = state != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+        final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
+        if (isVisible && !visibleActivities.contains(activity)) {
+            visibleActivities.add(activity);
+        } else if (!isVisible) {
+            visibleActivities.remove(activity);
+            if (visibleActivities.isEmpty()) {
+                // No need to keep the entry if there are no visible activities.
+                mPackageUidToCompatStateInfo.remove(packageUid);
+            }
+        }
+
+        if (state == lastLoggedState) {
+            // We don’t want to log the same state twice or log DEFAULT_NOT_VISIBLE before any
+            // visible state was logged.
+            return;
+        }
+
+        if (!isVisible && !visibleActivities.isEmpty()) {
+            // There is another visible activity for this package UID.
+            if (activity == lastLoggedActivity) {
+                // Make sure a new visible state is logged if needed.
+                findAppCompatStateToLog(compatStateInfo, packageUid);
+            }
+            return;
+        }
+
+        if (activity != lastLoggedActivity
+                && lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE
+                && lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED) {
+            // Another visible activity for this package UID has logged a letterboxed state.
+            return;
+        }
+
+        logAppCompatStateInternal(activity, state, packageUid, compatStateInfo);
+    }
+
+    /**
+     * Looks for the first visible activity in {@code compatStateInfo} that has a letterboxed
+     * state, or a non-letterboxed state if there isn't one, and logs that state for the given
+     * {@code packageUid}.
+     */
+    private void findAppCompatStateToLog(PackageCompatStateInfo compatStateInfo, int packageUid) {
+        final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
+
+        ActivityRecord activityToLog = null;
+        int stateToLog = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+        for (int i = 0; i < visibleActivities.size(); i++) {
+            ActivityRecord activity = visibleActivities.get(i);
+            int state = activity.getAppCompatState();
+            if (state == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
+                // This shouldn't happen.
+                Slog.w(TAG, "Visible activity with NOT_VISIBLE App Compat state for package UID: "
+                        + packageUid);
+                continue;
+            }
+            if (stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE || (
+                    stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED
+                            && state != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED)) {
+                activityToLog = activity;
+                stateToLog = state;
+            }
+        }
+        if (activityToLog != null && stateToLog != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
+            logAppCompatStateInternal(activityToLog, stateToLog, packageUid, compatStateInfo);
+        }
+    }
+
+    private void logAppCompatStateInternal(@NonNull ActivityRecord activity, int state,
+            int packageUid, PackageCompatStateInfo compatStateInfo) {
+        compatStateInfo.mLastLoggedState = state;
+        compatStateInfo.mLastLoggedActivity = activity;
+        FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPAT_STATE_CHANGED, packageUid, state);
+
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, String.format("APP_COMPAT_STATE_CHANGED(%s, %s)", packageUid, state));
+        }
+    }
+
     private ArtManagerInternal getArtManagerInternal() {
         if (mArtManagerInternal == null) {
             // Note that this may be null.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e6e18fd..c7f9254 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -127,6 +127,11 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityRecord.State.DESTROYED;
@@ -280,7 +285,6 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.os.storage.StorageManager;
 import android.service.contentcapture.ActivityEvent;
 import android.service.dreams.DreamActivity;
 import android.service.dreams.DreamManagerInternal;
@@ -312,7 +316,7 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.TransitionOldType;
 import android.view.animation.Animation;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.SizeConfigurationBuckets;
 import android.window.SplashScreen;
 import android.window.SplashScreenView;
@@ -486,7 +490,7 @@
     private ActivityOptions mPendingOptions;
     /** Non-null if {@link #mPendingOptions} specifies the remote animation. */
     private RemoteAnimationAdapter mPendingRemoteAnimation;
-    private IRemoteTransition mPendingRemoteTransition;
+    private RemoteTransition mPendingRemoteTransition;
     ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
     AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
     ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
@@ -676,6 +680,12 @@
     boolean mLastImeShown;
 
     /**
+     * When set to true, the IME insets will be frozen until the next app becomes IME input target.
+     * @see InsetsPolicy#adjustVisibilityForIme
+     */
+    boolean mImeInsetsFrozenUntilStartInput;
+
+    /**
      * A flag to determine if this AR is in the process of closing or entering PIP. This is needed
      * to help AR know that the app is in the process of closing but hasn't yet started closing on
      * the WM side.
@@ -719,7 +729,7 @@
     // TODO: rename to mNoDisplay
     @VisibleForTesting
     boolean noDisplay;
-    boolean mShowForAllUsers;
+    final boolean mShowForAllUsers;
     // TODO: Make this final
     int mTargetSdk;
 
@@ -1011,7 +1021,8 @@
             pw.println(mPendingRemoteAnimation.getCallingPid());
         }
         if (mPendingRemoteTransition != null) {
-            pw.print(prefix + " pendingRemoteTransition=" + mPendingRemoteTransition);
+            pw.print(prefix + " pendingRemoteTransition="
+                    + mPendingRemoteTransition.getRemoteTransition());
         }
         if (appTimeTracker != null) {
             appTimeTracker.dumpWithHeader(pw, prefix, false);
@@ -1179,7 +1190,7 @@
             header.run();
         }
 
-        String innerPrefix = prefix + "      ";
+        String innerPrefix = prefix + "  ";
         String[] args = new String[0];
         if (lastTask != r.getTask()) {
             lastTask = r.getTask();
@@ -1343,14 +1354,8 @@
                 updatePictureInPictureMode(null, false);
             } else {
                 mLastReportedMultiWindowMode = inMultiWindowMode;
-                // If the activity is in stopping or stopped state, for instance, it's in the
-                // split screen task and not the top one, the last configuration it should keep
-                // is the one before multi-window mode change.
-                final State state = getState();
-                if (state != STOPPED && state != STOPPING) {
-                    ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
-                            true /* ignoreVisibility */);
-                }
+                ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
+                        false /* ignoreVisibility */);
             }
         }
     }
@@ -1460,6 +1465,7 @@
                 associateStartingDataWithTask();
                 overrideConfigurationPropagation(mStartingWindow, task);
             }
+            mImeInsetsFrozenUntilStartInput = false;
         }
 
         if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -2444,20 +2450,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
@@ -2597,6 +2589,13 @@
         return task != null ? task.getOrganizedTask() : null;
     }
 
+    /** Returns the organized parent {@link TaskFragment}. */
+    @Nullable
+    TaskFragment getOrganizedTaskFragment() {
+        final TaskFragment parent = getTaskFragment();
+        return parent != null ? parent.getOrganizedTaskFragment() : null;
+    }
+
     @Override
     @Nullable
     TaskDisplayArea getDisplayArea() {
@@ -3008,7 +3007,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,
@@ -3248,6 +3247,20 @@
         // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
         final ActivityRecord next = getDisplayArea().topRunningActivity(
                 true /* considerKeyguardState */);
+
+        // If the finishing activity is the last activity of a organized TaskFragment and has an
+        // adjacent TaskFragment, check if the activity removal should be delayed.
+        boolean delayRemoval = false;
+        final TaskFragment taskFragment = getTaskFragment();
+        if (next != null && taskFragment != null && taskFragment.isEmbedded()) {
+            final TaskFragment organized = taskFragment.getOrganizedTaskFragment();
+            final TaskFragment adjacent =
+                    organized != null ? organized.getAdjacentTaskFragment() : null;
+            if (adjacent != null && organized.topRunningActivity() == null) {
+                delayRemoval = organized.isDelayLastActivityRemoval();
+            }
+        }
+
         // isNextNotYetVisible is to check if the next activity is invisible, or it has been
         // requested to be invisible but its windows haven't reported as invisible.  If so, it
         // implied that the current finishing activity should be added into stopping list rather
@@ -3262,7 +3275,7 @@
         }
 
         if (isCurrentVisible) {
-            if (isNextNotYetVisible) {
+            if (isNextNotYetVisible || delayRemoval) {
                 // Add this activity to the list of stopping activities. It will be processed and
                 // destroyed when the next activity reports idle.
                 addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
@@ -3470,7 +3483,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();
@@ -3681,18 +3696,33 @@
         }
         cleanUp(true /* cleanServices */, true /* setState */);
         if (remove) {
+            if (mStartingData != null && mVisible && task != null) {
+                // A corner case that the app terminates its trampoline activity on a separated
+                // process by killing itself. Transfer the starting window to the next activity
+                // which will be visible, so the dead activity can be removed immediately (no
+                // longer animating) and the reveal animation can play normally on next activity.
+                final ActivityRecord top = task.topRunningActivity();
+                if (top != null && !top.mVisible && top.shouldBeVisible()) {
+                    top.transferStartingWindow(this);
+                }
+            }
             removeFromHistory("appDied");
         }
     }
 
     @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();
     }
 
@@ -3911,7 +3941,9 @@
         if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
             // In this case, the starting icon has already been displayed, so start
             // letting windows get shown immediately without any more transitions.
-            getDisplayContent().mSkipAppTransitionAnimation = true;
+            if (fromActivity.mVisible) {
+                mDisplayContent.mSkipAppTransitionAnimation = true;
+            }
 
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s"
                     + " from %s to %s", tStartingWindow, fromActivity, this);
@@ -4276,7 +4308,7 @@
         // The activity now gets access to the data associated with this Intent.
         mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
                 getUriPermissionsLocked());
-        final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
+        final ReferrerIntent rintent = new ReferrerIntent(intent, getFilteredReferrer(referrer));
         boolean unsent = true;
         final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping();
 
@@ -4547,8 +4579,8 @@
         return opts;
     }
 
-    IRemoteTransition takeRemoteTransition() {
-        IRemoteTransition out = mPendingRemoteTransition;
+    RemoteTransition takeRemoteTransition() {
+        RemoteTransition out = mPendingRemoteTransition;
         mPendingRemoteTransition = null;
         return out;
     }
@@ -4666,6 +4698,7 @@
                 ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
         mTaskSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
         mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+        logAppCompatState();
     }
 
     @VisibleForTesting
@@ -4861,6 +4894,15 @@
             // getting visible so we also wait for them.
             forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
         }
+        // dispatchTaskInfoChangedIfNeeded() right after ActivityRecord#setVisibility() can report
+        // the stale visible state, because the state will be updated after the app transition.
+        // So tries to report the actual visible state again where the state is changed.
+        if (!mTaskSupervisor.inActivityVisibilityUpdate()) {
+            final Task task = getOrganizedTask();
+            if (task != null) {
+                task.dispatchTaskInfoChangedIfNeeded(false /* force */);
+            }
+        }
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
                 isVisible(), mVisibleRequested);
@@ -4923,6 +4965,7 @@
                     && imeInputTarget.getWindow().mActivityRecord == this
                     && mDisplayContent.mInputMethodWindow != null
                     && mDisplayContent.mInputMethodWindow.isVisible();
+            mImeInsetsFrozenUntilStartInput = true;
         }
 
         final DisplayContent displayContent = getDisplayContent();
@@ -5267,7 +5310,7 @@
 
     void updateVisibilityIgnoringKeyguard(boolean behindFullscreenActivity) {
         visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
-                && okToShowLocked();
+                && showToCurrentUser();
     }
 
     boolean shouldBeVisible() {
@@ -6054,6 +6097,14 @@
             // closing activity having to wait until idle timeout to be stopped or destroyed if the
             // next activity won't report idle (e.g. repeated view animation).
             mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+
+            // If the activity is visible, but no windows are eligible to start input, unfreeze
+            // to avoid permanently frozen IME insets.
+            if (mImeInsetsFrozenUntilStartInput && getWindow(
+                    win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
+                    == null) {
+                mImeInsetsFrozenUntilStartInput = false;
+            }
         }
     }
 
@@ -6296,22 +6347,8 @@
         return this;
     }
 
-    /** Checks whether the activity should be shown for current user. */
-    public boolean okToShowLocked() {
-        // We cannot show activities when the device is locked and the application is not
-        // encryption aware.
-        if (!StorageManager.isUserKeyUnlocked(mUserId)
-                && !info.applicationInfo.isEncryptionAware()) {
-            return false;
-        }
-
-        return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
-                || (mTaskSupervisor.isCurrentProfileLocked(mUserId)
-                && mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */));
-    }
-
     boolean canBeTopRunning() {
-        return !finishing && okToShowLocked();
+        return !finishing && showToCurrentUser();
     }
 
     /**
@@ -6626,17 +6663,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);
@@ -6930,7 +6956,7 @@
         Rect appRect;
         if (win != null) {
             insets = win.getInsetsStateWithVisibilityOverride().calculateInsets(
-                    win.getFrame(), Type.systemBars(), false /* ignoreVisibility */);
+                    win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect();
             appRect = new Rect(win.getFrame());
             appRect.inset(insets);
         } else {
@@ -7086,7 +7112,7 @@
             return;
         }
 
-        mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform(task);
+        mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform();
         // Perform rotation animation according to the rotation of this activity.
         startFreezingScreen(originalDisplayRotation);
         // This activity may relaunch or perform configuration change so once it has reported drawn,
@@ -7416,6 +7442,8 @@
             }
             resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
         }
+
+        logAppCompatState();
     }
 
     /**
@@ -7425,18 +7453,55 @@
      * LetterboxUiController#shouldShowLetterboxUi} for more context.
      */
     boolean areBoundsLetterboxed() {
+        return getAppCompatState(/* ignoreVisibility= */ true)
+                != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+    }
+
+    /**
+     * Logs the current App Compat state via {@link ActivityMetricsLogger#logAppCompatState}.
+     */
+    private void logAppCompatState() {
+        mTaskSupervisor.getActivityMetricsLogger().logAppCompatState(this);
+    }
+
+    /**
+     * Returns the current App Compat state of this activity.
+     *
+     * <p>The App Compat state indicates whether the activity is visible and letterboxed, and if so
+     * what is the reason for letterboxing. The state is used for logging the time spent in
+     * letterbox (sliced by the reason) vs non-letterbox per app.
+     */
+    int getAppCompatState() {
+        return getAppCompatState(/* ignoreVisibility= */ false);
+    }
+
+    /**
+     * Same as {@link #getAppCompatState()} except when {@code ignoreVisibility} the visibility
+     * of the activity is ignored.
+     *
+     * @param ignoreVisibility whether to ignore the visibility of the activity and not return
+     *                         NOT_VISIBLE if {@code mVisibleRequested} is false.
+     */
+    private int getAppCompatState(boolean ignoreVisibility) {
+        if (!ignoreVisibility && !mVisibleRequested) {
+            return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+        }
         if (mInSizeCompatModeForBounds) {
-            return true;
+            return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
         }
         // Letterbox for fixed orientation. This check returns true only when an activity is
         // letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
         // present. But this doesn't return true when the activity is letterboxed only because
         // of aspect ratio restrictions.
         if (isLetterboxedForFixedOrientationAndAspectRatio()) {
-            return true;
+            return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
         }
         // Letterbox for limited aspect ratio.
-        return mIsAspectRatioApplied;
+        if (mIsAspectRatioApplied) {
+            return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
+        }
+
+        return APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
     }
 
     /**
@@ -8049,6 +8114,13 @@
         }
     }
 
+    @Override
+    void onResize() {
+        // Reset freezing IME insets flag when the activity resized.
+        mImeInsetsFrozenUntilStartInput = false;
+        super.onResize();
+    }
+
     /** Returns true if the configuration is compatible with this activity. */
     boolean isConfigurationCompatible(Configuration config) {
         final int orientation = getRequestedOrientation();
@@ -8337,7 +8409,9 @@
                 startFreezingScreenLocked(globalChanges);
             }
             forceNewConfig = false;
-            preserveWindow &= isResizeOnlyChange(changes);
+            // Do not preserve window if it is freezing screen because the original window won't be
+            // able to update drawn state that causes freeze timeout.
+            preserveWindow &= isResizeOnlyChange(changes) && !mFreezingScreen;
             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
             if (hasResizeChange) {
                 final boolean isDragResizing = task.isDragResizing();
@@ -8741,6 +8815,19 @@
     }
 
     /**
+     * Gets the referrer package name with respect to package visibility. This method returns null
+     * if the given package is not visible to this activity.
+     */
+    String getFilteredReferrer(String referrerPackage) {
+        if (referrerPackage == null || (!referrerPackage.equals(packageName)
+                && mWmService.mPmInternal.filterAppAccess(
+                        referrerPackage, info.applicationInfo.uid, mUserId))) {
+            return null;
+        }
+        return referrerPackage;
+    }
+
+    /**
      * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
      * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
      * should be visible depending on Keyguard state.
@@ -9137,7 +9224,7 @@
             return null;
         }
         final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
-                task.getBounds(), Type.systemBars(), false /* ignoreVisibility */);
+                task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
         InsetUtils.addInsets(insets, getLetterboxInsets());
 
         return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
@@ -9191,6 +9278,11 @@
         super.finishSync(outMergedTransaction, cancel);
     }
 
+    @Override
+    boolean canBeAnimationTarget() {
+        return true;
+    }
+
     static class Builder {
         private final ActivityTaskManagerService mAtmService;
         private WindowProcessController mCallerApp;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c9f3356..3b43e48 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -115,7 +115,7 @@
 import android.util.DebugUtils;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -1509,7 +1509,7 @@
         final Task targetTask = r.getTask() != null
                 ? r.getTask()
                 : mTargetTask;
-        if (startedActivityRootTask == null || targetTask == null) {
+        if (startedActivityRootTask == null || targetTask == null || !targetTask.isAttached()) {
             return;
         }
 
@@ -1568,7 +1568,7 @@
         final Transition newTransition = (!mService.getTransitionController().isCollecting()
                 && mService.getTransitionController().getTransitionPlayer() != null)
                 ? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null;
-        IRemoteTransition remoteTransition = r.takeRemoteTransition();
+        RemoteTransition remoteTransition = r.takeRemoteTransition();
         if (newTransition != null && remoteTransition != null) {
             newTransition.setRemoteTransition(remoteTransition);
         }
@@ -1798,7 +1798,7 @@
         mRootWindowContainer.startPowerModeLaunchIfNeeded(
                 false /* forceSend */, mStartActivity);
 
-        final boolean isTaskSwitch = startedTask != prevTopTask;
+        final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
         mTargetRootTask.startActivityLocked(mStartActivity,
                 topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
                 isTaskSwitch, mOptions, sourceRecord);
@@ -2357,7 +2357,7 @@
         // of this in the record so that we can skip it when trying to find
         // the top running activity.
         mDoResume = doResume;
-        if (!doResume || !r.okToShowLocked() || mLaunchTaskBehind) {
+        if (!doResume || !r.showToCurrentUser() || mLaunchTaskBehind) {
             r.delayedResume = true;
             mDoResume = false;
         }
@@ -2682,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
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 25827cf..19cf14f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1908,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 */);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index fd64cf8..e6aa4fc 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. */
@@ -851,9 +857,9 @@
                         // and override configs.
                         mergedConfiguration.getGlobalConfiguration(),
                         mergedConfiguration.getOverrideConfiguration(), r.compat,
-                        r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
-                        r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
-                        r.takeOptions(), isTransitionForward,
+                        r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
+                        proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
+                        results, newIntents, r.takeOptions(), isTransitionForward,
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                         r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
                         r.getLaunchedFromBubble(), fragmentToken));
@@ -1866,12 +1872,6 @@
         mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget();
     }
 
-    /** Checks whether the userid is a profile of the current user. */
-    boolean isCurrentProfileLocked(int userId) {
-        if (userId == mRootWindowContainer.mCurrentUser) return true;
-        return mService.mAmInternal.isCurrentProfile(userId);
-    }
-
     /**
      * Processes the activities to be stopped or destroyed. This should be called when the resumed
      * activities are idle or drawn.
@@ -2297,6 +2297,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.
      *
@@ -2582,7 +2590,10 @@
         }
 
         boolean matches(ActivityRecord r) {
-            return mTargetComponent.equals(r.mActivityComponent) || mLaunchingState.contains(r);
+            if (!mLaunchingState.hasActiveTransitionInfo()) {
+                return mTargetComponent.equals(r.mActivityComponent);
+            }
+            return mLaunchingState.contains(r);
         }
 
         void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 174b396..929ac56f 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -40,6 +40,9 @@
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
@@ -474,6 +477,7 @@
         mNextAppTransitionAnimationsSpecsFuture = null;
         mDefaultNextAppTransitionAnimationSpec = null;
         mAnimationFinishedCallback = null;
+        mOverrideTaskTransition = false;
         mNextAppTransitionIsSync = false;
     }
 
@@ -939,7 +943,7 @@
                     "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
                             + "anim=%s transit=%s isEntrance=true Callers=%s",
                     a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (transit == TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE) {
+        } else if (isChangeTransitOld(transit)) {
             // In the absence of a specific adapter, we just want to keep everything stationary.
             a = new AlphaAnimation(1.f, 1.f);
             a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
@@ -1005,6 +1009,21 @@
                     animAttr = enter
                             ? WindowAnimation_launchTaskBehindSourceAnimation
                             : WindowAnimation_launchTaskBehindTargetAnimation;
+                    break;
+                // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
+                //  need new TaskFragment transition.
+                case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
+                    animAttr = enter
+                            ? WindowAnimation_activityOpenEnterAnimation
+                            : WindowAnimation_activityOpenExitAnimation;
+                    break;
+                // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
+                //  need new TaskFragment transition.
+                case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
+                    animAttr = enter
+                            ? WindowAnimation_activityCloseEnterAnimation
+                            : WindowAnimation_activityCloseExitAnimation;
+                    break;
             }
             a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
@@ -1315,6 +1334,15 @@
             case TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE: {
                 return "TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE";
             }
+            case TRANSIT_OLD_TASK_FRAGMENT_OPEN: {
+                return "TRANSIT_OLD_TASK_FRAGMENT_OPEN";
+            }
+            case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: {
+                return "TRANSIT_OLD_TASK_FRAGMENT_CLOSE";
+            }
+            case TRANSIT_OLD_TASK_FRAGMENT_CHANGE: {
+                return "TRANSIT_OLD_TASK_FRAGMENT_CHANGE";
+            }
             default: {
                 return "<UNKNOWN: " + transition + ">";
             }
@@ -1572,7 +1600,8 @@
     }
 
     static boolean isChangeTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+        return transit == TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE
+                || transit == TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
     }
 
     static boolean isClosingTransitOld(@TransitionOldType int transit) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index c869ec6..7a42351 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -39,6 +39,9 @@
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
@@ -68,6 +71,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.os.Trace;
 import android.util.ArrayMap;
@@ -82,10 +86,13 @@
 import android.view.WindowManager.TransitionOldType;
 import android.view.WindowManager.TransitionType;
 import android.view.animation.Animation;
+import android.window.ITaskFragmentOrganizer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.function.Predicate;
@@ -102,6 +109,20 @@
     private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
     private static final int KEYGUARD_GOING_AWAY_ANIMATION_DURATION = 400;
 
+    private static final int TYPE_NONE = 0;
+    private static final int TYPE_ACTIVITY = 1;
+    private static final int TYPE_TASK_FRAGMENT = 2;
+    private static final int TYPE_TASK = 3;
+
+    @IntDef(prefix = { "TYPE_" }, value = {
+            TYPE_NONE,
+            TYPE_ACTIVITY,
+            TYPE_TASK_FRAGMENT,
+            TYPE_TASK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface TransitContainerType {}
+
     private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>();
 
     AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
@@ -185,8 +206,8 @@
                 mDisplayContent.mOpeningApps);
 
         final @TransitionOldType int transit = getTransitCompatType(
-                mDisplayContent.mAppTransition,
-                mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
+                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
                 mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
                 mDisplayContent.mSkipAppTransitionAnimation);
         mDisplayContent.mSkipAppTransitionAnimation = false;
@@ -213,7 +234,11 @@
         final ActivityRecord topChangingApp =
                 getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
         final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
-        overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+
+        // Check if there is any override
+        if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
+            overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+        }
 
         final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
                 || containsVoiceInteraction(mDisplayContent.mOpeningApps);
@@ -267,6 +292,7 @@
      * @param appTransition {@link AppTransition} for managing app transition state.
      * @param openingApps {@link ActivityRecord}s which are becoming visible.
      * @param closingApps {@link ActivityRecord}s which are becoming invisible.
+     * @param changingContainers {@link WindowContainer}s which are changed in configuration.
      * @param wallpaperTarget If non-null, this is the currently visible window that is associated
      *                        with the wallpaper.
      * @param oldWallpaper The currently visible window that is associated with the wallpaper in
@@ -275,8 +301,8 @@
      */
     static @TransitionOldType int getTransitCompatType(AppTransition appTransition,
             ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
-            @Nullable WindowState wallpaperTarget, @Nullable WindowState oldWallpaper,
-            boolean skipAppTransitionAnimation) {
+            ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
+            @Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
 
         // Determine if closing and opening app token sets are wallpaper targets, in which case
         // special animations are needed.
@@ -309,8 +335,18 @@
 
         // Special transitions
         // TODO(new-app-transitions): Revisit if those can be rewritten by using flags.
-        if (appTransition.containsTransitRequest(TRANSIT_CHANGE)) {
-            return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+        if (appTransition.containsTransitRequest(TRANSIT_CHANGE) && !changingContainers.isEmpty()) {
+            @TransitContainerType int changingType =
+                    getTransitContainerType(changingContainers.valueAt(0));
+            switch (changingType) {
+                case TYPE_TASK:
+                    return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+                case TYPE_TASK_FRAGMENT:
+                    return TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+                default:
+                    throw new IllegalStateException(
+                            "TRANSIT_CHANGE with unrecognized changing type=" + changingType);
+            }
         }
         if ((flags & TRANSIT_FLAG_APP_CRASHED) != 0) {
             return TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
@@ -387,33 +423,38 @@
                 openingApps, closingApps, true /* visible */);
         final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
                 openingApps, closingApps, false /* visible */);
-        final boolean isActivityOpening = !openingWcs.isEmpty()
-                && openingWcs.valueAt(0).asActivityRecord() != null;
-        final boolean isActivityClosing = !closingWcs.isEmpty()
-                && closingWcs.valueAt(0).asActivityRecord() != null;
-        final boolean isTaskOpening = !openingWcs.isEmpty() && !isActivityOpening;
-        final boolean isTaskClosing = !closingWcs.isEmpty() && !isActivityClosing;
-
-        if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && isTaskOpening) {
+        final WindowContainer<?> openingContainer = !openingWcs.isEmpty()
+                ? openingWcs.valueAt(0) : null;
+        final WindowContainer<?> closingContainer = !closingWcs.isEmpty()
+                ? closingWcs.valueAt(0) : null;
+        @TransitContainerType int openingType = getTransitContainerType(openingContainer);
+        @TransitContainerType int closingType = getTransitContainerType(closingContainer);
+        if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && openingType == TYPE_TASK) {
             return TRANSIT_OLD_TASK_TO_FRONT;
         }
-        if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && isTaskClosing) {
+        if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && closingType == TYPE_TASK) {
             return TRANSIT_OLD_TASK_TO_BACK;
         }
         if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
-            if (isTaskOpening) {
+            if (openingType == TYPE_TASK) {
                 return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0
                         ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN;
             }
-            if (isActivityOpening) {
+            if (openingType == TYPE_ACTIVITY) {
                 return TRANSIT_OLD_ACTIVITY_OPEN;
             }
+            if (openingType == TYPE_TASK_FRAGMENT) {
+                return TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+            }
         }
         if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
-            if (isTaskClosing) {
+            if (closingType == TYPE_TASK) {
                 return TRANSIT_OLD_TASK_CLOSE;
             }
-            if (isActivityClosing) {
+            if (closingType == TYPE_TASK_FRAGMENT) {
+                return TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+            }
+            if (closingType == TYPE_ACTIVITY) {
                 for (int i = closingApps.size() - 1; i >= 0; i--) {
                     if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
                         return TRANSIT_OLD_ACTIVITY_CLOSE;
@@ -430,6 +471,24 @@
         return TRANSIT_OLD_NONE;
     }
 
+    @TransitContainerType
+    private static int getTransitContainerType(@Nullable WindowContainer<?> container) {
+        if (container == null) {
+            return TYPE_NONE;
+        }
+        if (container.asTask() != null) {
+            return TYPE_TASK;
+        }
+        if (container.asTaskFragment() != null) {
+            return TYPE_TASK_FRAGMENT;
+        }
+        if (container.asActivityRecord() != null) {
+            return TYPE_ACTIVITY;
+        }
+        return TYPE_NONE;
+    }
+
+    @Nullable
     private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) {
         final WindowState mainWindow = activity != null ? activity.findMainWindow() : null;
         return mainWindow != null ? mainWindow.mAttrs : null;
@@ -453,6 +512,61 @@
     }
 
     /**
+     * Overrides the pending transition with the remote animation defined by the
+     * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
+     * {@link TaskFragment} that are organized by the same organizer.
+     *
+     * @return {@code true} if the transition is overridden.
+     */
+    @VisibleForTesting
+    boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
+            ArraySet<Integer> activityTypes) {
+        final ArrayList<WindowContainer> allWindows = new ArrayList<>();
+        allWindows.addAll(mDisplayContent.mClosingApps);
+        allWindows.addAll(mDisplayContent.mOpeningApps);
+        allWindows.addAll(mDisplayContent.mChangingContainers);
+
+        // Find the common TaskFragmentOrganizer of all windows.
+        ITaskFragmentOrganizer organizer = null;
+        for (int i = allWindows.size() - 1; i >= 0; i--) {
+            final ActivityRecord r = getAppFromContainer(allWindows.get(i));
+            if (r == null) {
+                return false;
+            }
+            final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
+            final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null
+                    ? organizedTaskFragment.getTaskFragmentOrganizer()
+                    : null;
+            if (curOrganizer == null) {
+                // All windows must below an organized TaskFragment.
+                return false;
+            }
+            if (organizer == null) {
+                organizer = curOrganizer;
+            } else if (!organizer.asBinder().equals(curOrganizer.asBinder())) {
+                // They must be controlled by the same organizer.
+                return false;
+            }
+        }
+
+        final RemoteAnimationDefinition definition = organizer != null
+                ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
+                    .getRemoteAnimationDefinition(organizer)
+                : null;
+        final RemoteAnimationAdapter adapter = definition != null
+                ? definition.getAdapter(transit, activityTypes)
+                : null;
+        if (adapter == null) {
+            return false;
+        }
+        mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                "Override with TaskFragment remote animation for transit=%s",
+                AppTransition.appTransitionOldToString(transit));
+        return true;
+    }
+
+    /**
      * Overrides the pending transition with the remote animation defined for the transition in the
      * set of defined remote animations in the app window token.
      */
@@ -464,19 +578,21 @@
         }
         final RemoteAnimationAdapter adapter =
                 getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
-        if (adapter != null) {
+        if (adapter != null
+                && mDisplayContent.mAppTransition.getRemoteAnimationController() == null) {
             mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
         }
     }
 
     static ActivityRecord getAppFromContainer(WindowContainer wc) {
-        return wc.asTask() != null ? wc.asTask().getTopNonFinishingActivity()
+        return wc.asTaskFragment() != null ? wc.asTaskFragment().getTopNonFinishingActivity()
                 : wc.asActivityRecord();
     }
 
     /**
      * @return The window token that determines the animation theme.
      */
+    @Nullable
     private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit,
             ArraySet<Integer> activityTypes) {
         ActivityRecord result;
@@ -489,7 +605,7 @@
                 w -> w.getRemoteAnimationDefinition() != null
                         && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
         if (result != null) {
-            return getAppFromContainer(result);
+            return result;
         }
         result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
                 w -> w.fillsParent() && w.findMainWindow() != null);
@@ -632,6 +748,7 @@
             boolean canPromote = true;
 
             if (parent == null || !parent.canCreateRemoteAnimationTarget()
+                    || !parent.canBeAnimationTarget()
                     // We cannot promote the animation on Task's parent when the task is in
                     // clearing task in case the animating get stuck when performing the opening
                     // task that behind it.
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 b2e7b8f..e934cb8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -61,7 +61,6 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
@@ -87,6 +86,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LAYER_MIRRORING;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
@@ -294,6 +294,28 @@
      */
     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, or null if layer mirroring is
+     * temporarily disabled.
+     */
+    private SurfaceControl mMirroredSurface = null;
+
+    /**
+     * The last bounds of the DisplayArea to mirror.
+     */
+    private Rect mLastMirroredDisplayAreaBounds = null;
+
+    /**
+     * The last state of the display.
+     */
+    private int mLastDisplayState;
+
     // 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
@@ -771,10 +793,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;
+                }
             }
         }
 
@@ -1172,10 +1203,10 @@
         }
     }
 
-    WindowToken removeWindowToken(IBinder binder) {
+    WindowToken removeWindowToken(IBinder binder, boolean animateExit) {
         final WindowToken token = mTokenMap.remove(binder);
         if (token != null && token.asActivityRecord() == null) {
-            token.setExiting();
+            token.setExiting(animateExit);
         }
         return token;
     }
@@ -1253,7 +1284,7 @@
     }
 
     void removeAppToken(IBinder binder) {
-        final WindowToken token = removeWindowToken(binder);
+        final WindowToken token = removeWindowToken(binder, true /* animateExit */);
         if (token == null) {
             Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
             return;
@@ -1594,8 +1625,10 @@
             // If the transition has not started yet, the activity must be the top.
             return false;
         }
-        if (mLastWallpaperVisible && r.windowsCanBeWallpaperTarget()) {
-            // Use normal rotation animation for orientation change of visible wallpaper.
+        if (mLastWallpaperVisible && r.windowsCanBeWallpaperTarget()
+                && mFixedRotationTransitionListener.mAnimatingRecents == null) {
+            // Use normal rotation animation for orientation change of visible wallpaper if recents
+            // animation is not running (it may be swiping to home).
             return false;
         }
         final int rotation = rotationForActivityInDifferentOrientation(r);
@@ -2465,6 +2498,48 @@
         // Update IME parent if needed.
         updateImeParent();
 
+        // Update mirroring surface for MediaProjection, if this DisplayContent is being used
+        // for layer mirroring.
+        if (isCurrentlyMirroring() && mLastMirroredDisplayAreaBounds != null) {
+            // Mirroring has already begun, but update mirroring since the display is now on.
+            final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+                    mTokenToMirror);
+            if (wc == null) {
+                ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                        "Unable to retrieve window container to update layer mirroring for "
+                                + "display %d",
+                        mDisplayId);
+                return;
+            }
+
+            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                    "Display %d was already layer mirroring, so apply transformations if necessary",
+                    mDisplayId);
+            // 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) {
+                Point surfaceSize = fetchSurfaceSizeIfPresent();
+                if (surfaceSize != null) {
+                    ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                            "Going ahead with updating layer mirroring for display %d to new "
+                                    + "bounds %s and/or orientation %d.",
+                            mDisplayId, displayAreaBounds, displayAreaOrientation);
+                    updateMirroredSurface(mWmService.mTransactionFactory.get(),
+                            displayAreaBounds, surfaceSize);
+                } else {
+                    // If the surface removed, do nothing. We will handle this via onDisplayChanged
+                    // (the display will be off if the surface is removed).
+                    ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                            "Unable to update layer mirroring for display %d to new bounds %s"
+                            + " and/or orientation %d, since the surface is not available.",
+                            mDisplayId, displayAreaBounds, displayAreaOrientation);
+                }
+            }
+        }
+
         if (lastOrientation != getConfiguration().orientation) {
             getMetricsLogger().write(
                     new LogMaker(MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED)
@@ -3083,6 +3158,12 @@
         return mScreenRotationAnimation;
     }
 
+    /** If the display is in transition, there should be a screenshot covering it. */
+    @Override
+    boolean inTransition() {
+        return mScreenRotationAnimation != null || super.inTransition();
+    }
+
     @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
@@ -3774,6 +3855,23 @@
         return mWmService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay && !isPrivate();
     }
 
+    /** @see WindowManagerInternal#onToggleImeRequested */
+    void onShowImeRequested() {
+        if (mImeLayeringTarget == null || mInputMethodWindow == null) {
+            return;
+        }
+        // If IME window will be shown on the rotated activity, share the transformed state to
+        // IME window so it can compute rotated frame with rotated configuration.
+        if (mImeLayeringTarget.mToken.isFixedRotationTransforming()) {
+            mInputMethodWindow.mToken.linkFixedRotationTransform(mImeLayeringTarget.mToken);
+            // Hide the window until the rotation is done to avoid intermediate artifacts if the
+            // parent surface of IME container is changed.
+            if (mFadeRotationAnimationController != null) {
+                mFadeRotationAnimationController.hideImmediately(mInputMethodWindow.mToken);
+            }
+        }
+    }
+
     @VisibleForTesting
     void setImeLayeringTarget(WindowState target) {
         mImeLayeringTarget = target;
@@ -3949,6 +4047,9 @@
     void updateImeInputAndControlTarget(WindowState target) {
         if (mImeInputTarget != target) {
             ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
+            if (target != null && target.mActivityRecord != null) {
+                target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
+            }
             setImeInputTarget(target);
             updateImeControlTarget();
         }
@@ -4323,6 +4424,8 @@
                     mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
                     true /* inTraversal, must call performTraversalInTrans... below */);
         }
+        // If the display now has content, or no longer has content, update layer mirroring.
+        updateMirroring();
 
         final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
         if (wallpaperVisible != mLastWallpaperVisible) {
@@ -4577,7 +4680,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;
             }
 
@@ -5386,6 +5491,15 @@
             } else if (displayState == Display.STATE_ON) {
                 mOffTokenAcquirer.release(mDisplayId);
             }
+            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                    "Display %d state is now (%d), so update layer mirroring?",
+                    mDisplayId, displayState);
+            if (mLastDisplayState != displayState) {
+                // If state is on due to surface being added, then start layer mirroring.
+                // If state is off due to surface being removed, then stop layer mirroring.
+                updateMirroring();
+            }
+            mLastDisplayState = displayState;
         }
         mWmService.requestTraversal();
     }
@@ -5674,6 +5788,13 @@
         }
         mRemoved = true;
 
+        if (mMirroredSurface != null) {
+            // Do not wait for the mirrored surface to be garbage collected, but clean up
+            // immediately.
+            mWmService.mTransactionFactory.get().remove(mMirroredSurface).apply();
+            mMirroredSurface = null;
+        }
+
         // Only update focus/visibility for the last one because there may be many root tasks are
         // reparented and the intermediate states are unnecessary.
         if (lastReparentedRootTask != null) {
@@ -5851,6 +5972,182 @@
         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, is not mirroring already,
+        // and if this display is on (it has a surface to write output to).
+        if (mLastHasContent || isCurrentlyMirroring() || mDisplay.getState() == Display.STATE_OFF) {
+            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);
+            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                    "Unable to retrieve window container to start layer mirroring for display %d",
+                    mDisplayId);
+            return;
+        }
+
+        Point surfaceSize = fetchSurfaceSizeIfPresent();
+        if (surfaceSize == null) {
+            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                    "Unable to start layer mirroring for display %d since the surface is not "
+                            + "available.",
+                    mDisplayId);
+            return;
+        }
+        ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                "Display %d has no content and is on, so start layer mirroring for state %d",
+                mDisplayId, mDisplay.getState());
+
+        // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
+        SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
+        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(), surfaceSize);
+        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 mirroring if this DisplayContent no longer has content. Stop mirroring if it now
+     * has content or the display is not on.
+     */
+    private void updateMirroring() {
+        if (isCurrentlyMirroring() && (mLastHasContent
+                || mDisplay.getState() == Display.STATE_OFF)) {
+            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                    "Display %d has content (%b) so disable layer mirroring", mDisplayId,
+                    mLastHasContent);
+            // If the display is not on and it is a virtual display, then it no longer has an
+            // associated surface to write output to.
+            // If the display now has content, 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 {
+            // Display no longer has content, or now has a surface to write to, so try to 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.
+     * @param surfaceSize       the default size of the surface to write the display area content to
+     */
+    @VisibleForTesting
+    void updateMirroredSurface(SurfaceControl.Transaction transaction,
+            Rect displayAreaBounds, Point surfaceSize) {
+        // 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);
+    }
+
+    /**
+     * Returns a non-null {@link Point} if the surface is present, or null otherwise
+     */
+    Point fetchSurfaceSizeIfPresent() {
+        // 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.
+        Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
+                mDisplayId);
+        if (surfaceSize == null) {
+            // Layer mirroring started with a null surface, so do not apply any transformations yet.
+            // State of virtual display will change to 'ON' when the surface is set.
+            // will get event DISPLAY_DEVICE_EVENT_CHANGED
+            ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+                    "Provided surface for layer mirroring on display %d is not present, so do not"
+                            + " update the surface",
+                    mDisplayId);
+            return null;
+        }
+        return surfaceSize;
+    }
+
+    /**
+     * Returns {@code true} if this DisplayContent is currently layer mirroring.
+     */
+    boolean isCurrentlyMirroring() {
+        return mTokenToMirror != null && mMirroredSurface != null;
+    }
+
     /** 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 801182c..322024d 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -54,6 +54,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -377,6 +378,8 @@
 
     private PointerLocationView mPointerLocationView;
 
+    private int mDisplayCutoutTouchableRegionSize;
+
     /**
      * The area covered by system windows which belong to another display. Forwarded insets is set
      * in case this is a virtual display, this is displayed on another display that has insets, and
@@ -480,7 +483,8 @@
                             if (mStatusBar != null) {
                                 requestTransientBars(mStatusBar);
                             }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
+                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP,
+                                    false /* allowForAllPositions */);
                         }
                     }
 
@@ -491,7 +495,8 @@
                                     && mNavigationBarPosition == NAV_BAR_BOTTOM) {
                                 requestTransientBars(mNavigationBar);
                             }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
+                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM,
+                                    false /* allowForAllPositions */);
                         }
                     }
 
@@ -501,13 +506,13 @@
                         synchronized (mLock) {
                             mDisplayContent.calculateSystemGestureExclusion(
                                     excludedRegion, null /* outUnrestricted */);
-                            final boolean excluded =
-                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
+                            final boolean allowSideSwipe = mNavigationBarAlwaysShowOnSideGesture &&
+                                    !mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                             if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
-                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                    || allowSideSwipe)) {
                                 requestTransientBars(mNavigationBar);
                             }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
+                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT, allowSideSwipe);
                         }
                         excludedRegion.recycle();
                     }
@@ -518,13 +523,13 @@
                         synchronized (mLock) {
                             mDisplayContent.calculateSystemGestureExclusion(
                                     excludedRegion, null /* outUnrestricted */);
-                            final boolean excluded =
-                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
+                            final boolean allowSideSwipe = mNavigationBarAlwaysShowOnSideGesture &&
+                                    !mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                             if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
-                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                    || allowSideSwipe)) {
                                 requestTransientBars(mNavigationBar);
                             }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
+                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT, allowSideSwipe);
                         }
                         excludedRegion.recycle();
                     }
@@ -678,17 +683,19 @@
         mHandler.post(mGestureNavigationSettingsObserver::register);
     }
 
-    private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
-        if (mStatusBarAlt != null && mStatusBarAltPosition == pos) {
+    private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos,
+            boolean allowForAllPositions) {
+        if (mStatusBarAlt != null && (mStatusBarAltPosition == pos || allowForAllPositions)) {
             requestTransientBars(mStatusBarAlt);
         }
-        if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) {
+        if (mNavigationBarAlt != null
+                && (mNavigationBarAltPosition == pos || allowForAllPositions)) {
             requestTransientBars(mNavigationBarAlt);
         }
-        if (mClimateBarAlt != null && mClimateBarAltPosition == pos) {
+        if (mClimateBarAlt != null && (mClimateBarAltPosition == pos || allowForAllPositions)) {
             requestTransientBars(mClimateBarAlt);
         }
-        if (mExtraNavBarAlt != null && mExtraNavBarAltPosition == pos) {
+        if (mExtraNavBarAlt != null && (mExtraNavBarAltPosition == pos || allowForAllPositions)) {
             requestTransientBars(mExtraNavBarAlt);
         }
     }
@@ -872,6 +879,20 @@
     }
 
     /**
+     * Only trusted overlays are allowed to use FLAG_SLIPPERY.
+     */
+    static int sanitizeFlagSlippery(int flags, int privateFlags, String name) {
+        if ((flags & FLAG_SLIPPERY) == 0) {
+            return flags;
+        }
+        if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
+            return flags;
+        }
+        Slog.w(TAG, "Removing FLAG_SLIPPERY for non-trusted overlay " + name);
+        return flags & ~FLAG_SLIPPERY;
+    }
+
+    /**
      * Sanitize the layout parameters coming from a client.  Allows the policy
      * to do things like ensure that windows of a specific type can't take
      * input focus.
@@ -951,6 +972,8 @@
         if (mExtraNavBarAlt == win) {
             mExtraNavBarAltPosition = getAltBarPosition(attrs);
         }
+
+        attrs.flags = sanitizeFlagSlippery(attrs.flags, attrs.privateFlags, win.getName());
     }
 
     /**
@@ -1109,8 +1132,21 @@
                                 rect.bottom = rect.top + getStatusBarHeight(displayFrames);
                             }
                         };
+                final TriConsumer<DisplayFrames, WindowState, Rect> gestureFrameProvider =
+                        (displayFrames, windowState, rect) -> {
+                            rect.bottom = rect.top + getStatusBarHeight(displayFrames);
+                            final DisplayCutout cutout =
+                                    displayFrames.mInsetsState.getDisplayCutout();
+                            if (cutout != null) {
+                                final Rect top = cutout.getBoundingRectTop();
+                                if (!top.isEmpty()) {
+                                    rect.bottom = rect.bottom + mDisplayCutoutTouchableRegionSize;
+                                }
+                            }
+                        };
                 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
-                mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider);
+                mDisplayContent.setInsetProvider(
+                        ITYPE_TOP_MANDATORY_GESTURES, win, gestureFrameProvider);
                 mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
                 break;
             case TYPE_NAVIGATION_BAR:
@@ -1175,6 +1211,12 @@
             default:
                 if (attrs.providesInsetsTypes != null) {
                     for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
+                        final TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider =
+                                !attrs.providedInternalImeInsets.equals(Insets.NONE)
+                                    ? (displayFrames, windowState, inOutFrame) ->
+                                            inOutFrame.inset(windowState.getLayoutingAttrs(
+                                                displayFrames.mRotation).providedInternalImeInsets)
+                                    : null;
                         switch (insetsType) {
                             case ITYPE_STATUS_BAR:
                                 mStatusBarAlt = win;
@@ -1194,12 +1236,13 @@
                                 break;
                         }
                         if (!INSETS_LAYOUT_GENERALIZATION) {
-                            mDisplayContent.setInsetProvider(insetsType, win, null);
+                            mDisplayContent.setInsetProvider(insetsType, win, null,
+                                    imeFrameProvider);
                         } else {
                             mDisplayContent.setInsetProvider(insetsType, win, (displayFrames,
                                     windowState, inOutFrame) -> inOutFrame.inset(
                                             windowState.getLayoutingAttrs(displayFrames.mRotation)
-                                                    .providedInternalInsets));
+                                                    .providedInternalInsets), imeFrameProvider);
                         }
                     }
                 }
@@ -2091,11 +2134,14 @@
             mStatusBarHeightForRotation[landscapeRotation] =
                     mStatusBarHeightForRotation[seascapeRotation] =
                             res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+            mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize(
+                    R.dimen.display_cutout_touchable_region_size);
         } else {
             mStatusBarHeightForRotation[portraitRotation] =
                     mStatusBarHeightForRotation[upsideDownRotation] =
                             mStatusBarHeightForRotation[landscapeRotation] =
                                     mStatusBarHeightForRotation[seascapeRotation] = 0;
+            mDisplayCutoutTouchableRegionSize = 0;
         }
 
         // Height of the navigation bar when presented horizontally at bottom
@@ -2395,7 +2441,7 @@
      */
     float getWindowCornerRadius() {
         return mDisplayContent.getDisplay().getType() == TYPE_INTERNAL
-                ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
+                ? ScreenDecorationsUtils.getWindowCornerRadius(mContext) : 0f;
     }
 
     boolean isShowingDreamLw() {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index b627b33..4141090 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -19,6 +19,7 @@
 import android.content.res.Configuration;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.util.IntArray;
 import android.view.IDisplayWindowListener;
 
 /**
@@ -28,23 +29,20 @@
 class DisplayWindowListenerController {
     RemoteCallbackList<IDisplayWindowListener> mDisplayListeners = new RemoteCallbackList<>();
 
-//    private final ArrayList<DisplayContainerListener> mDisplayListeners = new ArrayList<>();
     private final WindowManagerService mService;
 
     DisplayWindowListenerController(WindowManagerService service) {
         mService = service;
     }
 
-    void registerListener(IDisplayWindowListener listener) {
+    int[] registerListener(IDisplayWindowListener listener) {
         synchronized (mService.mGlobalLock) {
             mDisplayListeners.register(listener);
-            try {
-                for (int i = 0; i < mService.mAtmService.mRootWindowContainer.getChildCount();
-                        ++i) {
-                    DisplayContent d = mService.mAtmService.mRootWindowContainer.getChildAt(i);
-                    listener.onDisplayAdded(d.mDisplayId);
-                }
-            } catch (RemoteException e) { }
+            final IntArray displayIds = new IntArray();
+            mService.mAtmService.mRootWindowContainer.forAllDisplays((displayContent) -> {
+                displayIds.add(displayContent.mDisplayId);
+            });
+            return displayIds.toArray();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 8fcdf2e..4a70fa3 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -264,8 +264,14 @@
 
     @NonNull
     private static AtomicFile getVendorSettingsFile() {
-        final File vendorFile = new File(Environment.getVendorDirectory(),
+        // First look under product path for treblized builds.
+        File vendorFile = new File(Environment.getProductDirectory(),
                 VENDOR_DISPLAY_SETTINGS_FILE_PATH);
+        if (!vendorFile.exists()) {
+            // Try and look in vendor path.
+            vendorFile = new File(Environment.getVendorDirectory(),
+                VENDOR_DISPLAY_SETTINGS_FILE_PATH);
+        }
         return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
     }
 
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 45f401b..fed4f62 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -23,6 +23,8 @@
 import android.annotation.Nullable;
 import android.util.Slog;
 
+import java.util.ArrayList;
+
 /** Helper class to ensure activities are in the right visible state for a container. */
 class EnsureActivitiesVisibleHelper {
     private final TaskFragment mTaskFragment;
@@ -98,17 +100,37 @@
                 && mTaskFragment.isTopActivityFocusable()
                 && (starting == null || !starting.isDescendantOf(mTaskFragment));
 
+        ArrayList<TaskFragment> adjacentTaskFragments = null;
         for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer child = mTaskFragment.mChildren.get(i);
             if (child.asTaskFragment() != null) {
                 final TaskFragment childTaskFragment = child.asTaskFragment();
                 childTaskFragment.updateActivityVisibilities(starting, configChanges,
                         preserveWindows, notifyClients);
-                mBehindFullyOccludedContainer = childTaskFragment.getBounds().equals(
+                mBehindFullyOccludedContainer |= childTaskFragment.getBounds().equals(
                         mTaskFragment.getBounds());
                 if (mAboveTop && mTop.getTaskFragment() == childTaskFragment) {
                     mAboveTop = false;
                 }
+
+                if (mBehindFullyOccludedContainer) {
+                    continue;
+                }
+
+                if (adjacentTaskFragments != null && adjacentTaskFragments.contains(
+                        childTaskFragment)) {
+                    // Everything behind two adjacent TaskFragments are occluded.
+                    mBehindFullyOccludedContainer = true;
+                    continue;
+                }
+
+                final TaskFragment adjacentTaskFrag = childTaskFragment.getAdjacentTaskFragment();
+                if (adjacentTaskFrag != null) {
+                    if (adjacentTaskFragments == null) {
+                        adjacentTaskFragments = new ArrayList<>();
+                    }
+                    adjacentTaskFragments.add(adjacentTaskFrag);
+                }
             } else if (child.asActivityRecord() != null) {
                 setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);
             }
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index eab3f10..52a7ac7 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -42,6 +42,9 @@
     /** A runnable which gets called when the {@link #show()} is called. */
     private Runnable mOnShowRunnable;
 
+    /** Whether to use constant zero alpha animation. */
+    private boolean mHideImmediately;
+
     public FadeRotationAnimationController(DisplayContent displayContent) {
         super(displayContent);
         mService = displayContent.mWmService;
@@ -51,6 +54,10 @@
                 mService.mWindowPlacerLocked.performSurfacePlacement();
             }
         } : null;
+        if (mFrozenTimeoutRunnable != null) {
+            // Hide the windows immediately because screen should have been covered by screenshot.
+            mHideImmediately = true;
+        }
         final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
         final WindowState navigationBar = displayPolicy.getNavigationBar();
         if (navigationBar != null) {
@@ -120,6 +127,15 @@
         }
     }
 
+    /** Hides the window immediately until it is drawn in new rotation. */
+    void hideImmediately(WindowToken windowToken) {
+        final boolean original = mHideImmediately;
+        mHideImmediately = true;
+        mTargetWindowTokens.add(windowToken);
+        fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
+        mHideImmediately = original;
+    }
+
     /** Returns {@code true} if the window is handled by this controller. */
     boolean isHandledToken(WindowToken token) {
         return token == mNavBarToken || isTargetToken(token);
@@ -145,8 +161,7 @@
 
     @Override
     public Animation getFadeOutAnimation() {
-        if (mFrozenTimeoutRunnable != null) {
-            // Hide the window immediately because screen should have been covered by screenshot.
+        if (mHideImmediately) {
             return new AlphaAnimation(0 /* fromAlpha */, 0 /* toAlpha */);
         }
         return super.getFadeOutAnimation();
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index 92baadf..5e8d795 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -22,12 +22,12 @@
 import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
 import android.util.ArraySet;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
-import com.android.server.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index aa7e6c9..18a2c60 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -30,6 +30,7 @@
 import android.view.InputApplicationHandle;
 import android.view.KeyEvent;
 import android.view.WindowManager;
+import android.view.WindowManagerPolicyConstants;
 
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.input.InputManagerService;
@@ -181,8 +182,8 @@
     @Override
     public int getPointerLayer() {
         return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER)
-                * WindowManagerService.TYPE_LAYER_MULTIPLIER
-                + WindowManagerService.TYPE_LAYER_OFFSET;
+                * WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER
+                + WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
     }
 
     /** Callback to get pointer display id. */
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index eb5ab83..f2e6abc 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;
 
@@ -46,6 +47,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
 
+import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Handler;
@@ -65,6 +67,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.Set;
 import java.util.function.Consumer;
 
@@ -99,6 +102,15 @@
     private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
 
     /**
+     * Set when recents (overview) is active as part of a shell transition. While set, any focus
+     * going to the recents activity will be redirected to the Recents input consumer. Since we
+     * draw the live-tile above the recents activity, we also need to provide that activity as a
+     * z-layering reference so that we can place the recents input consumer above it.
+     */
+    private WeakReference<ActivityRecord> mActiveRecentsActivity = null;
+    private WeakReference<ActivityRecord> mActiveRecentsLayerRef = null;
+
+    /**
      * Representation of a input consumer that the policy has added to the window manager to consume
      * input events going to windows below it.
      */
@@ -277,6 +289,7 @@
         inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures);
         inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
         inputWindowHandle.setVisible(w.isVisible());
+        inputWindowHandle.setWindowToken(w.mClient);
 
         final boolean focusable = w.canReceiveKeys()
                 && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
@@ -306,7 +319,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
@@ -391,6 +407,21 @@
     }
 
     /**
+     * Inform InputMonitor when recents is active so it can enable the recents input consumer.
+     * @param activity The active recents activity. {@code null} means recents is not active.
+     * @param layer An activity whose Z-layer is used as a reference for how to sort the consumer.
+     */
+    void setActiveRecents(@Nullable ActivityRecord activity, @Nullable ActivityRecord layer) {
+        final boolean clear = activity == null;
+        mActiveRecentsActivity = clear ? null : new WeakReference<>(activity);
+        mActiveRecentsLayerRef = clear ? null : new WeakReference<>(layer);
+    }
+
+    private static <T> T getWeak(WeakReference<T> ref) {
+        return ref != null ? ref.get() : null;
+    }
+
+    /**
      * Called when the current input focus changes.
      */
     private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) {
@@ -400,8 +431,10 @@
         if (recentsAnimationInputConsumer != null && focus != null) {
             final RecentsAnimationController recentsAnimationController =
                     mService.getRecentsAnimationController();
-            final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
-                    && recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord);
+            final boolean shouldApplyRecentsInputConsumer = (recentsAnimationController != null
+                    && recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord))
+                    // Shell transitions doesn't use RecentsAnimationController
+                    || getWeak(mActiveRecentsActivity) != null;
             if (shouldApplyRecentsInputConsumer) {
                 requestFocus(recentsAnimationInputConsumer.mWindowHandle.token,
                         recentsAnimationInputConsumer.mName);
@@ -501,6 +534,14 @@
             mInDrag = inDrag;
 
             resetInputConsumers(mInputTransaction);
+            // Update recents input consumer layer if active
+            if (mAddRecentsAnimationInputConsumerHandle
+                    && getWeak(mActiveRecentsActivity) != null) {
+                final WindowContainer layer = getWeak(mActiveRecentsLayerRef);
+                mRecentsAnimationInputConsumer.show(mInputTransaction,
+                        layer != null ? layer : getWeak(mActiveRecentsActivity));
+                mAddRecentsAnimationInputConsumerHandle = false;
+            }
             mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
             updateInputFocusRequest(mRecentsAnimationInputConsumer);
 
@@ -535,11 +576,16 @@
 
             final int privateFlags = w.mAttrs.privateFlags;
 
+            // This only works for legacy transitions.
             if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
                 if (recentsAnimationController.updateInputConsumerForApp(
                         mRecentsAnimationInputConsumer.mWindowHandle)) {
-                    mRecentsAnimationInputConsumer.show(mInputTransaction, w.mActivityRecord);
-                    mAddRecentsAnimationInputConsumerHandle = false;
+                    final WindowState highestLayerWindow =
+                            recentsAnimationController.getHighestLayerWindow();
+                    if (highestLayerWindow != null) {
+                        mRecentsAnimationInputConsumer.show(mInputTransaction, highestLayerWindow);
+                        mAddRecentsAnimationInputConsumerHandle = false;
+                    }
                 }
             }
 
@@ -648,6 +694,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/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index b4e11ff..6ce7b42 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.graphics.Region;
 import android.os.IBinder;
+import android.view.IWindow;
 import android.view.InputApplicationHandle;
 import android.view.InputWindowHandle;
 import android.view.SurfaceControl;
@@ -267,6 +268,14 @@
         mChanged = true;
     }
 
+    void setWindowToken(IWindow windowToken) {
+        if (mHandle.getWindow() == windowToken) {
+            return;
+        }
+        mHandle.setWindowToken(windowToken);
+        mChanged = true;
+    }
+
     @Override
     public String toString() {
         return mHandle + ", changed=" + mChanged;
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 895a82b..3d19f54 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;
@@ -47,11 +43,14 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.InsetsState.InternalInsetsType;
+import android.view.InternalInsetsAnimationController;
 import android.view.SurfaceControl;
 import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowInsets.Type;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimation.Bounds;
 import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowInsetsAnimationController;
 import android.view.WindowManager;
 
 import com.android.internal.R;
@@ -265,7 +264,7 @@
                 state.addSource(navSource);
                 return state;
             }
-        } else if (w.mActivityRecord != null && !w.mActivityRecord.mLastImeShown) {
+        } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
             // 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
@@ -273,14 +272,13 @@
             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))) {
+            if (shouldImeAttachedToApp && originalImeSource != null) {
+                final boolean imeVisibility =
+                        w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
                 final InsetsState state = copyState ? new InsetsState(originalState)
                         : originalState;
-
                 final InsetsSource imeSource = new InsetsSource(originalImeSource);
-                imeSource.setVisible(false);
+                imeSource.setVisible(imeVisibility);
                 state.addSource(imeSource);
                 return state;
             }
@@ -339,7 +337,7 @@
 
     private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
             boolean fake) {
-        if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1 && !fake) {
+        if (!fake && isShowingTransientTypes(Type.statusBars())) {
             return mDummyControlTarget;
         }
         final WindowState notificationShade = mPolicy.getNotificationShade();
@@ -389,7 +387,7 @@
             // Force showing navigation bar while IME is visible.
             return null;
         }
-        if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1 && !fake) {
+        if (!fake && isShowingTransientTypes(Type.navigationBars())) {
             return mDummyControlTarget;
         }
         if (focusedWin == mPolicy.getNotificationShade()) {
@@ -415,6 +413,16 @@
         return focusedWin;
     }
 
+    private boolean isShowingTransientTypes(@Type.InsetsType int types) {
+        final IntArray showingTransientTypes = mShowingTransientTypes;
+        for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
+            if ((InsetsState.toPublicType(showingTransientTypes.get(i)) & types) != 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Determines whether the remote insets controller should take control of system bars for all
      * windows.
@@ -589,8 +597,8 @@
             }
 
             @Override
-            public void startAnimation(InsetsAnimationControlImpl controller,
-                    WindowInsetsAnimationControlListener listener, int types,
+            public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+            void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
                     WindowInsetsAnimation animation,
                     Bounds bounds) {
             }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f3e52f2..f93e085 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -22,7 +22,7 @@
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
 import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH;
 import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE;
 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL;
@@ -164,7 +164,8 @@
             mWin.cancelAnimation();
             mWin.mProvidedInsetsSources.remove(mSource.getType());
         }
-        ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
+        ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource setWin %s for type %s", win,
+                InsetsState.typeToString(mSource.getType()));
         mWin = win;
         mFrameProvider = frameProvider;
         mImeFrameProvider = imeFrameProvider;
@@ -343,7 +344,7 @@
         updateVisibility();
         mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
                 mSource.calculateInsets(mWin.getBounds(), true /* ignoreVisibility */));
-        ProtoLog.d(WM_DEBUG_IME,
+        ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
                 "InsetsSource Control %s for target %s", mControl, mControlTarget);
     }
 
@@ -392,8 +393,9 @@
 
     protected void updateVisibility() {
         mSource.setVisible(mServerVisible && (isMirroredSource() || mClientVisible));
-        ProtoLog.d(WM_DEBUG_IME,
-                "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
+        ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
+                "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+                InsetsState.typeToString(mSource.getType()),
                 mServerVisible, mClientVisible);
     }
 
@@ -539,7 +541,7 @@
                 t.setAlpha(animationLeash, 1 /* alpha */);
                 t.hide(animationLeash);
             }
-            ProtoLog.i(WM_DEBUG_IME,
+            ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
                     "ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource,
                     mControlTarget);
 
@@ -555,7 +557,7 @@
                 mControlTarget = null;
                 mAdapter = null;
                 setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
-                ProtoLog.i(WM_DEBUG_IME,
+                ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
                         "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
                         mSource, mControlTarget);
             }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 2c4adcb..fd16a7d 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -16,9 +16,9 @@
 
 package com.android.server.wm;
 
+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.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
@@ -137,10 +137,10 @@
                 return rotatedState;
             }
         }
-        final @WindowingMode int windowingMode = token != null
-                ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
         final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
-        return getInsetsForTarget(type, windowingMode, alwaysOnTop, mState);
+        // Always use windowing mode fullscreen when get insets for window metrics to make sure it
+        // contains all insets types.
+        return getInsetsForTarget(type, WINDOWING_MODE_FULLSCREEN, alwaysOnTop, mState);
     }
 
     private static @InternalInsetsType
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 750de3b..4a8c36f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -27,6 +28,7 @@
 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_TO_BACK;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
@@ -235,8 +237,14 @@
                     mAodShowing ? 1 : 0,
                     1 /* keyguardGoingAway */,
                     "keyguardGoingAway");
-            mRootWindowContainer.getDefaultDisplay().requestTransitionAndLegacyPrepare(
-                    TRANSIT_KEYGUARD_GOING_AWAY, convertTransitFlags(flags));
+            final int transitFlags = convertTransitFlags(flags);
+            final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
+            dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, transitFlags);
+            // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
+            // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
+            // away.
+            dc.mAtmService.getTransitionController().requestTransitionIfNeeded(
+                    TRANSIT_TO_BACK, transitFlags, null /* trigger */, dc);
             updateKeyguardSleepToken();
 
             // Some stack visibility might change (e.g. docked stack)
@@ -276,7 +284,7 @@
     }
 
     private int convertTransitFlags(int keyguardGoingAwayFlags) {
-        int result = 0;
+        int result = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
         }
@@ -367,7 +375,7 @@
         // TODO(b/113840485): Handle app transition for individual display, and apply occluded
         // state change to secondary displays.
         // For now, only default display fully supports occluded change. Other displays only
-        // updates keygaurd sleep token on that display.
+        // updates keyguard sleep token on that display.
         if (displayId != DEFAULT_DISPLAY) {
             updateKeyguardSleepToken(displayId);
             return;
@@ -382,13 +390,6 @@
                                 isDisplayOccluded(DEFAULT_DISPLAY)
                                         ? TRANSIT_KEYGUARD_OCCLUDE
                                         : 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) {
-                    topActivity.mRequestForceTransition = true;
-                }
                 updateKeyguardSleepToken(DEFAULT_DISPLAY);
                 mWindowManager.executeAppTransition();
             } finally {
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index eb7087c..34b834b 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Color;
 
@@ -63,7 +64,10 @@
     private int mLetterboxActivityCornersRadius;
 
     // Color for {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} letterbox background type.
-    private Color mLetterboxBackgroundColor;
+    @Nullable private Color mLetterboxBackgroundColorOverride;
+
+    // Color resource id for {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} letterbox background type.
+    @Nullable private Integer mLetterboxBackgroundColorResourceIdOverride;
 
     @LetterboxBackgroundType
     private int mLetterboxBackgroundType;
@@ -81,20 +85,18 @@
     // side of the screen and 1.0 to the right side.
     private float mLetterboxHorizontalPositionMultiplier;
 
-    LetterboxConfiguration(Context context) {
-        mContext = context;
-        mFixedOrientationLetterboxAspectRatio = context.getResources().getFloat(
+    LetterboxConfiguration(Context systemUiContext) {
+        mContext = systemUiContext;
+        mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
                 R.dimen.config_fixedOrientationLetterboxAspectRatio);
-        mLetterboxActivityCornersRadius = context.getResources().getInteger(
+        mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
                 R.integer.config_letterboxActivityCornersRadius);
-        mLetterboxBackgroundColor = Color.valueOf(context.getResources().getColor(
-                R.color.config_letterboxBackgroundColor));
-        mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(context);
-        mLetterboxBackgroundWallpaperBlurRadius = context.getResources().getDimensionPixelSize(
+        mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
+        mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
                 R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
-        mLetterboxBackgroundWallpaperDarkScrimAlpha = context.getResources().getFloat(
+        mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(
                 R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
-        mLetterboxHorizontalPositionMultiplier = context.getResources().getFloat(
+        mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
                 R.dimen.config_letterboxHorizontalPositionMultiplier);
     }
 
@@ -158,12 +160,20 @@
     }
 
     /**
-     * Gets color of letterbox background which is  used when {@link
+     * Gets color of letterbox background which is used when {@link
      * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
      * fallback for other backfround types.
      */
     Color getLetterboxBackgroundColor() {
-        return mLetterboxBackgroundColor;
+        if (mLetterboxBackgroundColorOverride != null) {
+            return mLetterboxBackgroundColorOverride;
+        }
+        int colorId = mLetterboxBackgroundColorResourceIdOverride != null
+                ? mLetterboxBackgroundColorResourceIdOverride
+                : R.color.config_letterboxBackgroundColor;
+        // Query color dynamically because material colors extracted from wallpaper are updated
+        // when wallpaper is changed.
+        return Color.valueOf(mContext.getResources().getColor(colorId));
     }
 
 
@@ -173,7 +183,16 @@
      * fallback for other backfround types.
      */
     void setLetterboxBackgroundColor(Color color) {
-        mLetterboxBackgroundColor = color;
+        mLetterboxBackgroundColorOverride = color;
+    }
+
+    /**
+     * Sets color ID of letterbox background which is used when {@link
+     * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
+     * fallback for other backfround types.
+     */
+    void setLetterboxBackgroundColorResourceId(int colorId) {
+        mLetterboxBackgroundColorResourceIdOverride = colorId;
     }
 
     /**
@@ -181,8 +200,8 @@
      * com.android.internal.R.color.config_letterboxBackgroundColor}.
      */
     void resetLetterboxBackgroundColor() {
-        mLetterboxBackgroundColor = Color.valueOf(mContext.getResources().getColor(
-                com.android.internal.R.color.config_letterboxBackgroundColor));
+        mLetterboxBackgroundColorOverride = null;
+        mLetterboxBackgroundColorResourceIdOverride = null;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 4f7c9a4..6014a87 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -319,15 +319,11 @@
     }
 
     /** Resets the states which were used to perform fixed rotation with PiP task. */
-    void onCancelFixedRotationTransform(Task task) {
+    void onCancelFixedRotationTransform() {
         mFreezingTaskConfig = false;
         mDeferOrientationChanging = false;
         mDestRotatedBounds = null;
         mPipTransaction = null;
-        if (!task.isOrganized()) {
-            // Force clearing Task#mForceNotOrganized because the display didn't rotate.
-            task.onConfigurationChanged(task.getParent().getConfiguration());
-        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 4f93c7a..ba85c98 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -581,7 +581,7 @@
                 contentInsets = targetAppMainWindow
                         .getInsetsStateWithVisibilityOverride()
                         .calculateInsets(mTargetActivityRecord.getBounds(), Type.systemBars(),
-                                false /* ignoreVisibility */);
+                                false /* ignoreVisibility */).toRect();
             } else {
                 // If the window for the activity had not yet been created, use the display insets.
                 mService.getStableInsets(mDisplayId, mTmpRect);
@@ -1102,6 +1102,23 @@
         return mTargetActivityRecord.findMainWindow();
     }
 
+    /**
+     * Returns the window with the highest layer, or null if none is found.
+     */
+    public WindowState getHighestLayerWindow() {
+        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.getTopMostActivity().getTopChild();
+    }
+
     boolean isAnimatingTask(Task task) {
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             if (task == mPendingAnimations.get(i).mTask) {
@@ -1192,7 +1209,7 @@
                 return null;
             }
             final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
-                    mBounds, Type.systemBars(), false /* ignoreVisibility */);
+                    mBounds, Type.systemBars(), false /* ignoreVisibility */).toRect();
             InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
             final int mode = topApp.getActivityType() == mTargetActivityType
                     ? MODE_OPENING
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 1a429f8..6b57ede 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -396,6 +396,7 @@
         RemoteAnimationTarget mTarget;
         final WindowContainer mWindowContainer;
         final Rect mStartBounds;
+        private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING;
 
         RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
                 Rect endBounds, Rect startBounds) {
@@ -428,18 +429,12 @@
             return mTarget;
         }
 
+        void setMode(@RemoteAnimationTarget.Mode int mode) {
+            mMode = mode;
+        }
+
         int getMode() {
-            final DisplayContent dc = mWindowContainer.getDisplayContent();
-            final ActivityRecord topActivity = mWindowContainer.getTopMostActivity();
-            // Note that opening/closing transitions are per-activity while changing transitions
-            // are per-task.
-            if (dc.mOpeningApps.contains(topActivity)) {
-                return RemoteAnimationTarget.MODE_OPENING;
-            } else if (dc.mChangingContainers.contains(mWindowContainer)) {
-                return RemoteAnimationTarget.MODE_CHANGING;
-            } else {
-                return RemoteAnimationTarget.MODE_CLOSING;
-            }
+            return mMode;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index da3f983..6c2322b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1965,7 +1965,7 @@
 
     private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
             WindowProcessController app, ActivityRecord top) {
-        if (r.finishing || !r.okToShowLocked() || !r.visibleIgnoringKeyguard || r.app != null
+        if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard || r.app != null
                 || app.mUid != r.info.applicationInfo.uid || !app.mName.equals(r.processName)) {
             return false;
         }
@@ -1998,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;
         }
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 58363f2..d1460f4 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -18,6 +18,7 @@
 
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.RotationUtils.deltaRotation;
+import static android.view.WindowManagerPolicyConstants.SCREEN_FREEZE_LAYER_BASE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
@@ -30,8 +31,6 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;
 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.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
 
 import android.animation.ArgbEvaluator;
 import android.content.Context;
@@ -91,13 +90,6 @@
 class ScreenRotationAnimation {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM;
 
-    /*
-     * Layers for screen rotation animation. We put these layers above
-     * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows.
-     */
-    private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
-    private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
-
     private final Context mContext;
     private final DisplayContent mDisplayContent;
     private final float[] mTmpFloats = new float[9];
@@ -423,7 +415,7 @@
                         finalWidth * 2, finalHeight * 2);
                 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
                 mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
-                        SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false, mEnterBlackFrameLayer);
+                        SCREEN_FREEZE_LAYER_BASE, mDisplayContent, false, mEnterBlackFrameLayer);
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             }
@@ -737,7 +729,12 @@
                 mScreenshotRotationAnimator = null;
                 mRotateScreenAnimator = null;
                 mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
-                kill();
+                if (mDisplayContent.getRotationAnimation() == ScreenRotationAnimation.this) {
+                    // It also invokes kill().
+                    mDisplayContent.setRotationAnimation(null);
+                } else {
+                    kill();
+                }
                 mService.updateRotation(false, false);
             }
         }
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index 48a7bde..cdf6b08 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -27,6 +27,7 @@
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
+import android.view.WindowManagerPolicyConstants;
 
 class StrictModeFlash {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "StrictModeFlash" : TAG_WM;
@@ -52,7 +53,7 @@
                     .build();
 
             // one more than Watermark? arbitrary.
-            t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 101);
+            t.setLayer(ctrl, WindowManagerPolicyConstants.STRICT_MODE_LAYER);
             t.setPosition(ctrl, 0, 0);
             t.show(ctrl);
             // Ensure we aren't considered as obscuring for Input purposes.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 69ad59a..7bdb1a0 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;
@@ -591,16 +590,6 @@
     // false.
     private boolean mDeferTaskAppear;
 
-    /**
-     * Forces this task to be unorganized. Currently it is used for deferring the control of
-     * organizer when windowing mode is changing from PiP to fullscreen with orientation change.
-     * It is true only during Task#setWindowingMode ~ DisplayRotation#continueRotation.
-     *
-     * TODO(b/179235349): Remove this field by making surface operations from task organizer sync
-     *                    with display rotation.
-     */
-    private boolean mForceNotOrganized;
-
     // Tracking cookie for the creation of this task.
     IBinder mLaunchCookie;
 
@@ -723,7 +712,7 @@
             } catch (RemoteException e) {
             }
         }
-        if (autoRemoveFromRecents() || isVoiceSession) {
+        if (autoRemoveFromRecents(oldParent.asTaskFragment()) || isVoiceSession) {
             // Task creator asked to remove this when done, or this task was a voice
             // interaction, so it should not remain on the recent tasks list.
             mTaskSupervisor.mRecentTasks.remove(this);
@@ -1513,7 +1502,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
@@ -1543,7 +1532,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);
@@ -1575,11 +1567,12 @@
         return count > 0;
     }
 
-    private boolean autoRemoveFromRecents() {
+    private boolean autoRemoveFromRecents(TaskFragment oldParentFragment) {
         // We will automatically remove the task either if it has explicitly asked for
         // this, or it is empty and has never contained an activity that got shown to
-        // the user.
-        return autoRemoveRecents || (!hasChild() && !getHasBeenVisible());
+        // the user, or it was being embedded in another Task.
+        return autoRemoveRecents || (!hasChild() && !getHasBeenVisible()
+                || (oldParentFragment != null && oldParentFragment.isEmbedded()));
     }
 
     private void clearPinnedTaskIfNeed() {
@@ -1929,19 +1922,16 @@
             }
         }
 
-        if (pipChanging) {
-            // If the top activity is using fixed rotation, it should be changing from PiP to
-            // fullscreen with display orientation change. Do not notify fullscreen task organizer
-            // because the restoration of task surface and the transformation of activity surface
-            // need to be done synchronously.
+        if (pipChanging && wasInPictureInPicture) {
+            // If the top activity is changing from PiP to fullscreen with fixed rotation,
+            // clear the crop and rotation matrix of task because fixed rotation will handle
+            // the transformation on activity level. This also avoids flickering caused by the
+            // latency of fullscreen task organizer configuring the surface.
             final ActivityRecord r = topRunningActivity();
             if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) {
-                mForceNotOrganized = true;
+                getSyncTransaction().setWindowCrop(mSurfaceControl, null)
+                        .setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9]);
             }
-        } else {
-            // If the display orientation change is done, let the corresponding task organizer take
-            // back the control of this task.
-            mForceNotOrganized = false;
         }
 
         saveLaunchingStateIfNeeded();
@@ -2176,16 +2166,6 @@
         bounds.offset(horizontalDiff, verticalDiff);
     }
 
-    /**
-     * Initializes a change transition. See {@link SurfaceFreezer} for more information.
-     */
-    private void initializeChangeTransition(Rect startBounds) {
-        mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
-        mDisplayContent.mChangingContainers.add(this);
-
-        mSurfaceFreezer.freeze(getPendingTransaction(), startBounds);
-    }
-
     private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
         if (mWmService.mDisableTransitionAnimation
                 || !isVisible()
@@ -2594,25 +2574,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) {
@@ -3124,10 +3091,6 @@
         });
     }
 
-    boolean isFocusableAndVisible() {
-        return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
-    }
-
     void positionChildAtTop(ActivityRecord child) {
         positionChildAt(child, POSITION_TOP);
     }
@@ -3252,7 +3215,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) {
@@ -3262,7 +3225,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) {
@@ -3393,19 +3356,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--) {
@@ -3696,9 +3649,6 @@
         pw.print(" isResizeable="); pw.println(isResizeable());
         pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
         pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
-        if (mForceNotOrganized) {
-            pw.print(prefix); pw.println("mForceNotOrganized=true");
-        }
     }
 
     @Override
@@ -4174,10 +4124,6 @@
     }
 
     private boolean canBeOrganized() {
-        if (mForceNotOrganized || !mAtmService.mTaskOrganizerController
-                .isSupportedWindowingMode(getWindowingMode())) {
-            return false;
-        }
         // All root tasks can be organized
         if (isRootTask()) {
             return true;
@@ -4330,9 +4276,8 @@
             return setTaskOrganizer(null);
         }
 
-        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;
         }
@@ -4666,8 +4611,10 @@
             mAtmService.continueWindowLayout();
         }
 
-        mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
-        mRootWindowContainer.resumeFocusedTasksTopActivities();
+        if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
+            mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+            mRootWindowContainer.resumeFocusedTasksTopActivities();
+        }
     }
 
     void resumeNextFocusAfterReparent() {
@@ -5056,7 +5003,10 @@
             if (topFragment == f) {
                 return;
             }
-
+            if (!f.isFocusableAndVisible()) {
+                // No need to resume activity in TaskFragment that is not visible.
+                return;
+            }
             resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
         }, true);
         return resumed[0];
@@ -5209,7 +5159,7 @@
                 }
 
                 final ActivityRecord prev = baseTask.getActivity(
-                        a -> a.mStartingData != null && a.okToShowLocked());
+                        a -> a.mStartingData != null && a.showToCurrentUser());
                 r.showStartingWindow(prev, newTask, isTaskSwitch,
                         true /* startActivity */, sourceRecord);
             }
@@ -5358,18 +5308,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();
@@ -5592,7 +5530,7 @@
 
             // Don't refocus if invisible to current user
             final ActivityRecord top = tr.getTopNonFinishingActivity();
-            if (top == null || !top.okToShowLocked()) {
+            if (top == null || !top.showToCurrentUser()) {
                 positionChildAtTop(tr);
                 if (top != null) {
                     mTaskSupervisor.mRecentTasks.add(top.getTask());
@@ -5765,17 +5703,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,
@@ -6172,16 +6107,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 6c8cde43..c7ca180 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -32,6 +32,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
@@ -112,7 +113,6 @@
     private final ArrayList<WindowContainer> mTmpNormalChildren = new ArrayList<>();
     private final ArrayList<WindowContainer> mTmpHomeChildren = new ArrayList<>();
     private final IntArray mTmpNeedsZBoostIndexes = new IntArray();
-    private int mTmpLayerForSplitScreenDividerAnchor;
     private int mTmpLayerForAnimationLayer;
 
     private ArrayList<Task> mTmpTasks = new ArrayList<>();
@@ -855,26 +855,23 @@
         layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer, false /* normalRootTasks */);
         // The home animation layer is between the root home tasks and the normal root tasks.
         final int layerForHomeAnimationLayer = layer++;
-        mTmpLayerForSplitScreenDividerAnchor = layer++;
         mTmpLayerForAnimationLayer = layer++;
         layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer, true /* normalRootTasks */);
 
         // The boosted animation layer is between the normal root tasks and the always on top
         // root tasks.
         final int layerForBoostedAnimationLayer = layer++;
+        // Always on top tasks layer should higher than split divider layer so set it as start.
+        layer = SPLIT_DIVIDER_LAYER + 1;
         adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer, false /* normalRootTasks */);
 
         t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer);
         t.setLayer(mAppAnimationLayer, mTmpLayerForAnimationLayer);
-        t.setLayer(mSplitScreenDividerAnchor, mTmpLayerForSplitScreenDividerAnchor);
+        t.setLayer(mSplitScreenDividerAnchor, SPLIT_DIVIDER_LAYER);
         t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
     }
 
     private int adjustNormalRootTaskLayer(WindowContainer child, int layer) {
-        if (child.asTask() != null && child.inSplitScreenWindowingMode()) {
-            // The split screen divider anchor is located above the split screen window.
-            mTmpLayerForSplitScreenDividerAnchor = layer++;
-        }
         if ((child.asTask() != null && child.asTask().isAnimatingByRecents())
                 || child.isAppTransitioning()) {
             // The animation layer is located above the highest animating root task and no
@@ -2104,7 +2101,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 8a7688f..7c939e6 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -33,6 +33,7 @@
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_NONE;
@@ -61,6 +62,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,8 +161,8 @@
      */
     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 is adjacent to this one. */
     @Nullable
@@ -219,6 +222,13 @@
     private IBinder mFragmentToken;
 
     /**
+     * Whether to delay the last activity of TaskFragment being immediately removed while finishing.
+     * This should only be set on a embedded TaskFragment, where the organizer can have the
+     * opportunity to perform other actions or animations.
+     */
+    private boolean mDelayLastActivityRemoval;
+
+    /**
      * The PID of the organizer that created this TaskFragment. It should be the same as the PID
      * of {@link android.window.TaskFragmentCreationParams#getOwnerToken()}.
      * {@link ActivityRecord#INVALID_PID} if this is not an organizer-created TaskFragment.
@@ -315,8 +325,10 @@
         // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
         if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
             mAdjacentTaskFragment.mAdjacentTaskFragment = null;
+            mAdjacentTaskFragment.mDelayLastActivityRemoval = false;
         }
         mAdjacentTaskFragment = null;
+        mDelayLastActivityRemoval = false;
     }
 
     void setTaskFragmentOrganizer(TaskFragmentOrganizerToken organizer, int pid) {
@@ -420,6 +432,20 @@
     }
 
     /**
+     * Returns the TaskFragment that is being organized, which could be this or the ascendant
+     * TaskFragment.
+     */
+    @Nullable
+    TaskFragment getOrganizedTaskFragment() {
+        if (mTaskFragmentOrganizer != null) {
+            return this;
+        }
+
+        TaskFragment parentTaskFragment = getParent().asTaskFragment();
+        return parentTaskFragment != null ? parentTaskFragment.getOrganizedTaskFragment() : null;
+    }
+
+    /**
      * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}.
      */
     private void warnForNonLeafTaskFragment(String func) {
@@ -629,7 +655,6 @@
      * @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) {
@@ -1260,6 +1285,10 @@
         return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
     }
 
+    boolean isFocusableAndVisible() {
+        return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
+    }
+
     final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) {
         return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
     }
@@ -1398,6 +1427,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;
             }
 
@@ -1586,7 +1617,12 @@
     @Override
     RemoteAnimationTarget createRemoteAnimationTarget(
             RemoteAnimationController.RemoteAnimationRecord record) {
-        final ActivityRecord activity = getTopMostActivity();
+        final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
+                // There may be a trampoline activity without window on top of the existing task
+                // which is moving to front. Exclude the finishing activity so the window of next
+                // activity can be chosen to create the animation target.
+                ? getTopNonFinishingActivity()
+                : getTopMostActivity();
         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
     }
 
@@ -1951,10 +1987,50 @@
 
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
+        // Task will animate differently.
+        if (mTaskFragmentOrganizer != null) {
+            mTmpPrevBounds.set(getBounds());
+        }
+
         super.onConfigurationChanged(newParentConfig);
+
+        if (shouldStartChangeTransition(mTmpPrevBounds)) {
+            initializeChangeTransition(mTmpPrevBounds);
+        }
+
+        if (mTaskFragmentOrganizer != null) {
+            // Update the surface position here instead of in the organizer so that we can make sure
+            // it can be synced with the surface freezer.
+            updateSurfacePosition(getSyncTransaction());
+        }
+
         sendTaskFragmentInfoChanged();
     }
 
+    /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */
+    private boolean shouldStartChangeTransition(Rect startBounds) {
+        if (mWmService.mDisableTransitionAnimation
+                || mDisplayContent == null
+                || mTaskFragmentOrganizer == null
+                || getSurfaceControl() == null
+                // The change transition will be covered by display.
+                || mDisplayContent.inTransition()
+                || !isVisible()) {
+            return false;
+        }
+
+        return !startBounds.equals(getBounds());
+    }
+
+    /**
+     * Initializes a change transition. See {@link SurfaceFreezer} for more information.
+     */
+    void initializeChangeTransition(Rect startBounds) {
+        mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
+        mDisplayContent.mChangingContainers.add(this);
+        mSurfaceFreezer.freeze(getSyncTransaction(), startBounds);
+    }
+
     @Override
     void setSurfaceControl(SurfaceControl sc) {
         super.setSurfaceControl(sc);
@@ -2003,12 +2079,18 @@
         }
         final Point positionInParent = new Point();
         getRelativePosition(positionInParent);
+        final int[] runningActivityCount = new int[1];
+        forAllActivities(a -> {
+            if (!a.finishing) {
+                runningActivityCount[0]++;
+            }
+        });
         return new TaskFragmentInfo(
                 mFragmentToken,
                 mRemoteToken.toWindowContainerToken(),
                 getConfiguration(),
                 getChildCount() == 0,
-                hasRunningActivity(this),
+                runningActivityCount[0],
                 isVisible(),
                 childActivities,
                 positionInParent);
@@ -2020,11 +2102,15 @@
     }
 
     @Nullable
-    @VisibleForTesting
     ITaskFragmentOrganizer getTaskFragmentOrganizer() {
         return mTaskFragmentOrganizer;
     }
 
+    @Override
+    boolean isOrganized() {
+        return mTaskFragmentOrganizer != null;
+    }
+
     /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */
     void clearLastPausedActivity() {
         forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null);
@@ -2045,15 +2131,83 @@
     }
 
     @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);
+            }
+        });
+    }
+
+    void setDelayLastActivityRemoval(boolean delay) {
+        if (!mIsEmbedded) {
+            Slog.w(TAG, "Set delaying last activity removal on a non-embedded TF.");
+        }
+        mDelayLastActivityRemoval = delay;
+    }
+
+    boolean isDelayLastActivityRemoval() {
+        return mDelayLastActivityRemoval;
+    }
+
+    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;
+    }
+
+    @Override
+    boolean canBeAnimationTarget() {
+        return true;
     }
 
     boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
@@ -2081,10 +2235,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());
             }
@@ -2095,7 +2249,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);
@@ -2103,6 +2263,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 a322384..30d2a32 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -30,6 +30,7 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.view.RemoteAnimationDefinition;
 import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
 import android.window.ITaskFragmentOrganizerController;
@@ -81,6 +82,13 @@
         private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
                 new WeakHashMap<>();
 
+        /**
+         * @see android.window.TaskFragmentOrganizer#registerRemoteAnimations(
+         * RemoteAnimationDefinition)
+         */
+        @Nullable
+        private RemoteAnimationDefinition mRemoteAnimationDefinition;
+
         TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) {
             mOrganizer = organizer;
             try {
@@ -199,6 +207,8 @@
 
         void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
                 Throwable exception) {
+            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                    "Sending TaskFragment error exception=%s", exception.toString());
             final Bundle exceptionBundle = putExceptionInBundle(exception);
             try {
                 organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
@@ -230,11 +240,71 @@
         validateAndGetState(organizer);
         final int pid = Binder.getCallingPid();
         final long uid = Binder.getCallingUid();
+        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);
+        }
+    }
+
+    @Override
+    public void registerRemoteAnimations(ITaskFragmentOrganizer organizer,
+            RemoteAnimationDefinition definition) {
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
         synchronized (mGlobalLock) {
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
-                    "Unregister task fragment organizer=%s uid=%d pid=%d",
+                    "Register remote animations for organizer=%s uid=%d pid=%d",
                     organizer.asBinder(), uid, pid);
-            removeOrganizer(organizer);
+            final TaskFragmentOrganizerState organizerState =
+                    mTaskFragmentOrganizerState.get(organizer.asBinder());
+            if (organizerState == null) {
+                throw new IllegalStateException("The organizer hasn't been registered.");
+            }
+            if (organizerState.mRemoteAnimationDefinition != null) {
+                throw new IllegalStateException(
+                        "The organizer has already registered remote animations="
+                                + organizerState.mRemoteAnimationDefinition);
+            }
+
+            definition.setCallingPidUid(pid, uid);
+            organizerState.mRemoteAnimationDefinition = definition;
+        }
+    }
+
+    @Override
+    public void unregisterRemoteAnimations(ITaskFragmentOrganizer organizer) {
+        final int pid = Binder.getCallingPid();
+        final long uid = Binder.getCallingUid();
+        synchronized (mGlobalLock) {
+            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                    "Unregister remote animations for organizer=%s uid=%d pid=%d",
+                    organizer.asBinder(), uid, pid);
+            final TaskFragmentOrganizerState organizerState =
+                    mTaskFragmentOrganizerState.get(organizer.asBinder());
+            if (organizerState == null) {
+                Slog.e(TAG, "The organizer hasn't been registered.");
+                return;
+            }
+
+            organizerState.mRemoteAnimationDefinition = null;
+        }
+    }
+
+    /** Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. */
+    @Nullable
+    public RemoteAnimationDefinition getRemoteAnimationDefinition(
+            ITaskFragmentOrganizer organizer) {
+        synchronized (mGlobalLock) {
+            final TaskFragmentOrganizerState organizerState =
+                    mTaskFragmentOrganizerState.get(organizer.asBinder());
+            return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
         }
     }
 
@@ -308,6 +378,7 @@
     void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
             Throwable exception) {
         validateAndGetState(organizer);
+        Slog.w(TAG, "onTaskFragmentError ", exception);
         PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(organizer,
                 errorCallbackToken, exception, PendingTaskFragmentEvent.EVENT_ERROR);
         mPendingTaskFragmentEvents.add(pendingEvent);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 99f31ad..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;
 
@@ -373,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 */);
@@ -433,14 +417,8 @@
     /**
      * @return the task organizer key for a given windowing mode.
      */
-    ITaskOrganizer getTaskOrganizer(int windowingMode) {
-        return isSupportedWindowingMode(windowingMode)
-                ? mTaskOrganizers.peekLast()
-                : null;
-    }
-
-    boolean isSupportedWindowingMode(int winMode) {
-        return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
+    ITaskOrganizer getTaskOrganizer() {
+        return mTaskOrganizers.peekLast();
     }
 
     // Capture the animation surface control for activity's main window
@@ -680,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 {
@@ -993,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 54390dc..2805dce 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -689,7 +689,8 @@
     }
 
     static Rect getSystemBarInsets(Rect frame, InsetsState state) {
-        return state.calculateInsets(frame, Type.systemBars(), false /* ignoreVisibility */);
+        return state.calculateInsets(
+                frame, Type.systemBars(), false /* ignoreVisibility */).toRect();
     }
 
     void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 6bfa611..6b93364 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -16,13 +16,19 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 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.INPUT_CONSUMER_RECENTS_ANIMATION;
+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;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -36,6 +42,7 @@
 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;
@@ -63,7 +70,7 @@
 import android.util.Slog;
 import android.view.SurfaceControl;
 import android.view.animation.Animation;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -116,7 +123,7 @@
     private @TransitionFlags int mFlags;
     private final TransitionController mController;
     private final BLASTSyncEngine mSyncEngine;
-    private IRemoteTransition mRemoteTransition = null;
+    private RemoteTransition mRemoteTransition = null;
 
     /** Only use for clean-up after binder death! */
     private SurfaceControl.Transaction mStartTransaction = null;
@@ -135,6 +142,12 @@
     /** The final animation targets derived from participants after promotion. */
     private ArraySet<WindowContainer> mTargets = null;
 
+    /**
+     * Set of participating windowtokens (activity/wallpaper) which are visible at the end of
+     * the transition animation.
+     */
+    private final ArraySet<WindowToken> mVisibleAtTransitionEndTokens = new ArraySet<>();
+
     /** Custom activity-level animation options and callbacks. */
     private TransitionInfo.AnimationOptions mOverrideOptions;
     private IRemoteCallback mClientAnimationStartCallback = null;
@@ -146,7 +159,7 @@
     // TODO(b/188595497): remove when not needed.
     /** @see RecentsAnimationController#mNavigationBarAttachedToApp */
     private boolean mNavBarAttachedToApp = false;
-    private int mNavBarDisplayId = INVALID_DISPLAY;
+    private int mRecentsDisplayId = INVALID_DISPLAY;
 
     Transition(@TransitionType int type, @TransitionFlags int flags,
             TransitionController controller, BLASTSyncEngine syncEngine) {
@@ -166,6 +179,11 @@
         return mSyncId;
     }
 
+    @TransitionFlags
+    int getFlags() {
+        return mFlags;
+    }
+
     /**
      * Formally starts the transition. Participants can be collected before this is started,
      * but this won't consider itself ready until started -- even if all the participants have
@@ -341,7 +359,14 @@
         for (int i = 0; i < mParticipants.size(); ++i) {
             final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
             if (ar != null) {
-                if (!ar.isVisibleRequested()) {
+                boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(ar);
+                // We need both the expected visibility AND current requested-visibility to be
+                // false. If it is expected-visible but not currently visible, it means that
+                // another animation is queued-up to animate this to invisibility, so we can't
+                // remove the surfaces yet. If it is currently visible, but not expected-visible,
+                // then doing commitVisibility here would actually be out-of-order and leave the
+                // activity in a bad state.
+                if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
                     boolean commitVisibility = true;
                     if (ar.getDeferHidingClient() && ar.getTask() != null) {
                         if (ar.pictureInPictureArgs != null
@@ -364,17 +389,20 @@
                         activitiesWentInvisible = true;
                     }
                 }
-                if (mChanges.get(ar).mVisible != ar.isVisibleRequested()) {
+                if (mChanges.get(ar).mVisible != visibleAtTransitionEnd) {
                     // Legacy dispatch relies on this (for now).
-                    ar.mEnteringAnimation = ar.isVisibleRequested();
+                    ar.mEnteringAnimation = visibleAtTransitionEnd;
                 }
                 mController.dispatchLegacyAppTransitionFinished(ar);
             }
             final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
-            if (wt != null && !wt.isVisibleRequested()) {
-                ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
-                        "  Commit wallpaper becoming invisible: %s", wt);
-                wt.commitVisibility(false /* visible */);
+            if (wt != null) {
+                final boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(wt);
+                if (!visibleAtTransitionEnd && !wt.isVisibleRequested()) {
+                    ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                            "  Commit wallpaper becoming invisible: %s", wt);
+                    wt.commitVisibility(false /* visible */);
+                }
             }
         }
         if (activitiesWentInvisible) {
@@ -387,6 +415,13 @@
         sendRemoteCallback(mClientAnimationFinishCallback);
 
         legacyRestoreNavigationBarFromApp();
+
+        if (mRecentsDisplayId != INVALID_DISPLAY) {
+            // Clean up input monitors (for recents)
+            final DisplayContent dc =
+                    mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
+            dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
+        }
     }
 
     void abort() {
@@ -401,11 +436,11 @@
         mSyncEngine.abort(mSyncId);
     }
 
-    void setRemoteTransition(IRemoteTransition remoteTransition) {
+    void setRemoteTransition(RemoteTransition remoteTransition) {
         mRemoteTransition = remoteTransition;
     }
 
-    IRemoteTransition getRemoteTransition() {
+    RemoteTransition getRemoteTransition() {
         return mRemoteTransition;
     }
 
@@ -484,6 +519,15 @@
             }
         }
 
+        // Record windowtokens (activity/wallpaper) that are expected to be visible after the
+        // transition animation. This will be used in finishTransition to prevent prematurely
+        // committing visibility.
+        for (int i = mParticipants.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mParticipants.valueAt(i);
+            if (wc.asWindowToken() == null || !wc.isVisibleRequested()) continue;
+            mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
+        }
+
         mStartTransaction = transaction;
         mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
         buildFinishTransaction(mFinishTransaction, info.getRootLeash());
@@ -521,7 +565,7 @@
         if (mFinishTransaction != null) {
             mFinishTransaction.apply();
         }
-        finishTransition();
+        mController.finishTransition(this);
     }
 
     /** @see RecentsAnimationController#attachNavigationBarToApp */
@@ -531,7 +575,43 @@
         }
         final DisplayContent dc =
                 mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
-        if (dc == null || !dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
+        if (dc == null) return;
+        mRecentsDisplayId = displayId;
+
+        // Recents has an input-consumer to grab input from the "live tile" app. Set that up here
+        final InputConsumerImpl recentsAnimationInputConsumer =
+                dc.getInputMonitor().getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
+        if (recentsAnimationInputConsumer != null) {
+            // find the top-most going-away activity and the recents activity. The top-most
+            // is used as layer reference while the recents is used for registering the consumer
+            // override.
+            ActivityRecord recentsActivity = null;
+            ActivityRecord topActivity = null;
+            for (int i = 0; i < info.getChanges().size(); ++i) {
+                final TransitionInfo.Change change = info.getChanges().get(i);
+                if (change.getTaskInfo() == null) continue;
+                final Task task = Task.fromWindowContainerToken(
+                        info.getChanges().get(i).getTaskInfo().token);
+                if (task == null) continue;
+                final int activityType = change.getTaskInfo().topActivityType;
+                final boolean isRecents = activityType == ACTIVITY_TYPE_HOME
+                        || activityType == ACTIVITY_TYPE_RECENTS;
+                if (isRecents && recentsActivity == null) {
+                    recentsActivity = task.getTopVisibleActivity();
+                } else if (!isRecents && topActivity == null) {
+                    topActivity = task.getTopNonFinishingActivity();
+                }
+            }
+            if (recentsActivity != null && topActivity != null) {
+                recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(
+                        topActivity.getBounds());
+                dc.getInputMonitor().setActiveRecents(recentsActivity, topActivity);
+            }
+        }
+
+        // The rest of this function handles nav-bar reparenting
+
+        if (!dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
                 // Skip the case where the nav bar is controlled by fade rotation.
                 || dc.getFadeRotationAnimationController() != null) {
             return;
@@ -558,7 +638,6 @@
             return;
         }
         mNavBarAttachedToApp = true;
-        mNavBarDisplayId = displayId;
         navWindow.mToken.cancelAnimation();
         final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
         final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
@@ -582,12 +661,17 @@
         if (!mNavBarAttachedToApp) return;
         mNavBarAttachedToApp = false;
 
+        if (mRecentsDisplayId == INVALID_DISPLAY) {
+            Slog.e(TAG, "Reparented navigation bar without a valid display");
+            mRecentsDisplayId = DEFAULT_DISPLAY;
+        }
+
         if (mController.mStatusBar != null) {
-            mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mNavBarDisplayId, true);
+            mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mRecentsDisplayId, true);
         }
 
         final DisplayContent dc =
-                mController.mAtm.mRootWindowContainer.getDisplayContent(mNavBarDisplayId);
+                mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
         final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar();
         if (navWindow == null) return;
         navWindow.setSurfaceTranslationY(0);
@@ -619,13 +703,14 @@
     }
 
     private void handleNonAppWindowsInTransition(int displayId,
-            @TransitionType int transit, int flags) {
+            @TransitionType int transit, @TransitionFlags int flags) {
         final DisplayContent dc =
                 mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
         if (dc == null) {
             return;
         }
-        if (transit == TRANSIT_KEYGUARD_GOING_AWAY
+        if ((transit == TRANSIT_KEYGUARD_GOING_AWAY
+                || (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0)
                 && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
             if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
                     && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
@@ -657,7 +742,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
@@ -893,7 +978,7 @@
             // Wallpaper must be the top (regardless of how nested it is in DisplayAreas).
             boolean skipIntermediateReports = isWallpaper(wc);
             for (WindowContainer p = wc.getParent(); p != null; p = p.getParent()) {
-                if (!p.isAttached() || !changes.get(p).hasChanged(p)) {
+                if (!p.isAttached() || changes.get(p) == null || !changes.get(p).hasChanged(p)) {
                     // Again, we're skipping no-ops
                     break;
                 }
@@ -1066,6 +1151,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);
         }
@@ -1073,6 +1162,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);
     }
@@ -1166,6 +1272,9 @@
             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;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 44dee4d..69e6a54 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -18,11 +18,7 @@
 
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 
@@ -38,6 +34,7 @@
 import android.view.WindowManager;
 import android.window.IRemoteTransition;
 import android.window.ITransitionPlayer;
+import android.window.RemoteTransition;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 
@@ -121,11 +118,16 @@
 
     void registerTransitionPlayer(@Nullable ITransitionPlayer player) {
         try {
+            // Note: asBinder() can be null if player is same process (likely in a test).
             if (mTransitionPlayer != null) {
-                mTransitionPlayer.asBinder().unlinkToDeath(mTransitionPlayerDeath, 0);
+                if (mTransitionPlayer.asBinder() != null) {
+                    mTransitionPlayer.asBinder().unlinkToDeath(mTransitionPlayerDeath, 0);
+                }
                 mTransitionPlayer = null;
             }
-            player.asBinder().linkToDeath(mTransitionPlayerDeath, 0);
+            if (player.asBinder() != null) {
+                player.asBinder().linkToDeath(mTransitionPlayerDeath, 0);
+            }
             mTransitionPlayer = player;
         } catch (RemoteException e) {
             throw new RuntimeException("Unable to set transition player");
@@ -222,7 +224,7 @@
     @Nullable
     Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
             @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
-            @NonNull WindowContainer readyGroupRef, @Nullable IRemoteTransition remoteTransition) {
+            @NonNull WindowContainer readyGroupRef, @Nullable RemoteTransition remoteTransition) {
         if (mTransitionPlayer == null) {
             return null;
         }
@@ -230,6 +232,10 @@
         if (isCollecting()) {
             // Make the collecting transition wait until this request is ready.
             mCollectingTransition.setReady(readyGroupRef, false);
+            if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) {
+                // Add keyguard flag to dismiss keyguard
+                mCollectingTransition.addFlag(flags);
+            }
         } else {
             newTransition = requestStartTransition(createTransition(type, flags),
                     trigger != null ? trigger.asTask() : null, remoteTransition);
@@ -247,7 +253,7 @@
     /** Asks the transition player (shell) to start a created but not yet started transition. */
     @NonNull
     Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,
-            @Nullable IRemoteTransition remoteTransition) {
+            @Nullable RemoteTransition remoteTransition) {
         try {
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                     "Requesting StartTransition: %s", transition);
@@ -354,11 +360,7 @@
     }
 
     void dispatchLegacyAppTransitionStarting(TransitionInfo info) {
-        final boolean keyguardGoingAway = info.getType() == TRANSIT_KEYGUARD_GOING_AWAY
-                || (info.getFlags() & (TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE
-                        | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION
-                        | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER
-                        | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION)) != 0;
+        final boolean keyguardGoingAway = info.isKeyguardGoingAway();
         for (int i = 0; i < mLegacyListeners.size(); ++i) {
             mLegacyListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway,
                     0 /* durationHint */, SystemClock.uptimeMillis(),
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 0f61f1a..7893612 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -559,6 +559,9 @@
         final WindowState prevWallpaperTarget = mWallpaperTarget;
         mWallpaperTarget = wallpaperTarget;
 
+        if (prevWallpaperTarget == null && wallpaperTarget != null) {
+            updateWallpaperOffsetLocked(mWallpaperTarget, false);
+        }
         if (wallpaperTarget == null || prevWallpaperTarget == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 194f48f..b54e8b7 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -66,8 +66,8 @@
     }
 
     @Override
-    void setExiting() {
-        super.setExiting();
+    void setExiting(boolean animateExit) {
+        super.setExiting(animateExit);
         mDisplayContent.mWallpaperController.removeWallpaperToken(this);
     }
 
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index 66ab094..9780d33 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -31,6 +31,7 @@
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
+import android.view.WindowManagerPolicyConstants;
 
 /**
  * Displays a watermark on top of the window manager's windows.
@@ -117,7 +118,7 @@
                     .setFormat(PixelFormat.TRANSLUCENT)
                     .setCallsite(TITLE)
                     .build();
-            t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100)
+            t.setLayer(ctrl, WindowManagerPolicyConstants.WATERMARK_LAYER)
                     .setPosition(ctrl, 0, 0)
                     .show(ctrl);
             // Ensure we aren't considered as obscuring for Input purposes.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index c48e9d1..31bf49d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -51,6 +51,7 @@
 import static com.android.server.wm.WindowContainerProto.IDENTIFIER;
 import static com.android.server.wm.WindowContainerProto.ORIENTATION;
 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
+import static com.android.server.wm.WindowContainerProto.SURFACE_CONTROL;
 import static com.android.server.wm.WindowContainerProto.VISIBLE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -987,6 +988,10 @@
         return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
     }
 
+    boolean inTransition() {
+        return mWmService.mAtmService.getTransitionController().inTransition(this);
+    }
+
     void sendAppVisibilityToClients() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
@@ -1376,6 +1381,7 @@
         }
     }
 
+    /** Returns whether the window should be shown for current user. */
     boolean showToCurrentUser() {
         return true;
     }
@@ -2393,6 +2399,9 @@
         if (mSurfaceAnimator.isAnimating()) {
             mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
         }
+        if (mSurfaceControl != null) {
+            mSurfaceControl.dumpDebug(proto, SURFACE_CONTROL);
+        }
 
         // add children to proto
         for (int i = 0; i < getChildCount(); i++) {
@@ -2689,6 +2698,11 @@
             final RemoteAnimationController.RemoteAnimationRecord adapters =
                     controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
                             screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
+            if (!isChanging) {
+                adapters.setMode(enter
+                        ? RemoteAnimationTarget.MODE_OPENING
+                        : RemoteAnimationTarget.MODE_CLOSING);
+            }
             resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
         } else if (isChanging) {
             final float durationScale = mWmService.getTransitionAnimationScaleLocked();
@@ -2842,6 +2856,14 @@
         return false;
     }
 
+    /**
+     * {@code true} to indicate that this container can be a candidate of
+     * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) animation
+     * target}. */
+    boolean canBeAnimationTarget() {
+        return false;
+    }
+
     boolean okToDisplay() {
         final DisplayContent dc = getDisplayContent();
         return dc != null && dc.okToDisplay();
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index a5ebf9a..bdbcd16 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -21,9 +21,9 @@
 
 import android.provider.AndroidDeviceConfig;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
 import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 6a6d3c9..b8e303b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -461,8 +461,21 @@
      * @param removeWindows Whether to also remove the windows associated with the token.
      * @param displayId The display to remove the token from.
      */
+    public final void removeWindowToken(android.os.IBinder token, boolean removeWindows,
+            int displayId) {
+        removeWindowToken(token, removeWindows, true /* animateExit */, displayId);
+    }
+
+    /**
+     * Removes a window token.
+     *
+     * @param token The toke to remove.
+     * @param removeWindows Whether to also remove the windows associated with the token.
+     * @param animateExit Whether to play the windows exit animation after the token removal.
+     * @param displayId The display to remove the token from.
+     */
     public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows,
-            int displayId);
+            boolean animateExit, int displayId);
 
     /**
      * Registers a listener to be notified about app transition events.
@@ -675,24 +688,43 @@
     public abstract String getWindowName(@NonNull IBinder binder);
 
     /**
-     * Return the window name of IME Insets control target.
+     * The callback after the request of show/hide input method is sent.
      *
+     * @param show Whether to show or hide input method.
+     * @param focusedToken The token of focused window.
+     * @param requestToken The token of window who requests the change.
      * @param displayId The ID of the display which input method is currently focused.
-     * @return The corresponding {@link WindowState#getName()}
+     * @return The information of the input method target.
      */
-    public abstract @Nullable String getImeControlTargetNameForLogging(int displayId);
+    public abstract ImeTargetInfo onToggleImeRequested(boolean show,
+            @NonNull IBinder focusedToken, @NonNull IBinder requestToken, int displayId);
 
-    /**
-     * Return the current window name of the input method is on top of.
-     *
-     * Note that the concept of this window is only reparent the target window behind the input
-     * method window, it may different with the window which reported by
-     * {@code InputMethodManagerService#reportStartInput} which has input connection.
-     *
-     * @param displayId The ID of the display which input method is currently focused.
-     * @return The corresponding {@link WindowState#getName()}
-     */
-    public abstract @Nullable String getImeTargetNameForLogging(int displayId);
+    /** The information of input method target when IME is requested to show or hide. */
+    public static class ImeTargetInfo {
+        public final String focusedWindowName;
+        public final String requestWindowName;
+
+        /** The window name of IME Insets control target. */
+        public final String imeControlTargetName;
+
+        /**
+         * The current window name of the input method is on top of.
+         * <p>
+         * Note that the concept of this window is only used to reparent the target window behind
+         * the input method window, it may be different from the window reported by
+         * {@link com.android.server.inputmethod.InputMethodManagerService#reportStartInput} which
+         * has input connection.
+         */
+        public final String imeLayerTargetName;
+
+        public ImeTargetInfo(String focusedWindowName, String requestWindowName,
+                String imeControlTargetName, String imeLayerTargetName) {
+            this.focusedWindowName = focusedWindowName;
+            this.requestWindowName = requestWindowName;
+            this.imeControlTargetName = imeControlTargetName;
+            this.imeLayerTargetName = imeLayerTargetName;
+        }
+    }
 
     /**
      * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3a5d771..9458511 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -57,6 +57,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
 import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -85,8 +86,10 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
+import static android.window.WindowProviderService.isWindowProviderService;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
@@ -203,6 +206,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.DeviceConfigInterface;
 import android.provider.Settings;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -297,7 +301,6 @@
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.power.ShutdownThread;
-import com.android.server.utils.DeviceConfigInterface;
 import com.android.server.utils.PriorityDump;
 
 import java.io.BufferedWriter;
@@ -339,27 +342,6 @@
 
     static final boolean PROFILE_ORIENTATION = false;
 
-    /** How much to multiply the policy's type layer, to reserve room
-     * for multiple windows of the same type and Z-ordering adjustment
-     * with TYPE_LAYER_OFFSET. */
-    static final int TYPE_LAYER_MULTIPLIER = 10000;
-
-    /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
-     * or below others in the same layer. */
-    static final int TYPE_LAYER_OFFSET = 1000;
-
-    /** How much to increment the layer for each window, to reserve room
-     * for effect surfaces between them.
-     */
-    static final int WINDOW_LAYER_MULTIPLIER = 5;
-
-    /**
-     * Animation thumbnail is as far as possible below the window above
-     * the thumbnail (or in other words as far as possible above the window
-     * below it).
-     */
-    static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER - 1;
-
     /** The maximum length we will accept for a loaded animation duration:
      * this is 10 seconds.
      */
@@ -1236,7 +1218,9 @@
         mAssistantOnTopOfDream = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_assistantOnTopOfDream);
 
-        mLetterboxConfiguration = new LetterboxConfiguration(context);
+        mLetterboxConfiguration = new LetterboxConfiguration(
+                // Using SysUI context to have access to Material colors extracted from Wallpaper.
+                ActivityThread.currentActivityThread().getSystemUiContext());
 
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -1730,16 +1714,22 @@
                     && mWindowContextListenerController.hasListener(windowContextToken)) {
                 final int windowContextType = mWindowContextListenerController
                         .getWindowType(windowContextToken);
+                final Bundle options = mWindowContextListenerController
+                        .getOptions(windowContextToken);
                 if (type != windowContextType) {
                     ProtoLog.w(WM_ERROR, "Window types in WindowContext and"
                             + " LayoutParams.type should match! Type from LayoutParams is %d,"
                             + " but type from WindowContext is %d", type, windowContextType);
-                    return WindowManagerGlobal.ADD_INVALID_TYPE;
+                    // We allow WindowProviderService to add window other than windowContextType,
+                    // but the WindowProviderService won't be associated with the window's
+                    // WindowToken.
+                    if (!isWindowProviderService(options)) {
+                        return WindowManagerGlobal.ADD_INVALID_TYPE;
+                    }
+                } else {
+                    mWindowContextListenerController.registerWindowContainerListener(
+                            windowContextToken, token, callingUid, type, options);
                 }
-                final Bundle options = mWindowContextListenerController
-                        .getOptions(windowContextToken);
-                mWindowContextListenerController.registerWindowContainerListener(
-                        windowContextToken, token, callingUid, type, options);
             }
 
             // From now on, no exceptions or errors allowed!
@@ -2821,6 +2811,31 @@
 
     }
 
+    void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+            int displayId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
+
+            if (dc == null) {
+                ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+                        + " for non-exiting displayId=%d", binder, displayId);
+                return;
+            }
+            final WindowToken token = dc.removeWindowToken(binder, animateExit);
+            if (token == null) {
+                ProtoLog.w(WM_ERROR,
+                        "removeWindowToken: Attempted to remove non-existing token: %s",
+                        binder);
+                return;
+            }
+
+            if (removeWindows) {
+                token.removeAllWindowsIfPossible();
+            }
+            dc.getInputMonitor().updateInputWindowsLw(true /* force */);
+        }
+    }
+
     @Override
     public void removeWindowToken(IBinder binder, int displayId) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
@@ -2828,23 +2843,7 @@
         }
         final long origId = Binder.clearCallingIdentity();
         try {
-            synchronized (mGlobalLock) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-
-                if (dc == null) {
-                    ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
-                            + " for non-exiting displayId=%d", binder, displayId);
-                    return;
-                }
-                final WindowToken token = dc.removeWindowToken(binder);
-                if (token == null) {
-                    ProtoLog.w(WM_ERROR,
-                            "removeWindowToken: Attempted to remove non-existing token: %s",
-                            binder);
-                    return;
-                }
-                dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
-            }
+            removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -4342,13 +4341,18 @@
         }
     }
 
-    /** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */
+    /**
+     * Registers a hierarchy listener that gets callbacks when the hierarchy changes. The listener's
+     * onDisplayAdded() will not be called for the displays returned.
+     *
+     * @return the displayIds for the existing displays
+     */
     @Override
-    public void registerDisplayWindowListener(IDisplayWindowListener listener) {
+    public int[] registerDisplayWindowListener(IDisplayWindowListener listener) {
         mAtmService.enforceTaskPermission("registerDisplayWindowListener");
         final long ident = Binder.clearCallingIdentity();
         try {
-            mDisplayNotificationController.registerListener(listener);
+            return mDisplayNotificationController.registerListener(listener);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7086,6 +7090,7 @@
                             "requestScrollCapture: caught exception dispatching to window."
                                     + "token=%s", targetWindow.mClient.asBinder());
                     responseBuilder.setWindowTitle(targetWindow.getName());
+                    responseBuilder.setPackageName(targetWindow.getOwningPackage());
                     responseBuilder.setDescription(String.format("caught exception: %s", e));
                     listener.onScrollCaptureResponse(responseBuilder.build());
                 }
@@ -7559,28 +7564,10 @@
         }
 
         @Override
-        public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) {
-            synchronized (mGlobalLock) {
-                if (removeWindows) {
-                    final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                    if (dc == null) {
-                        ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
-                                + " for non-exiting displayId=%d", binder, displayId);
-                        return;
-                    }
-
-                    final WindowToken token = dc.removeWindowToken(binder);
-                    if (token == null) {
-                        ProtoLog.w(WM_ERROR,
-                                "removeWindowToken: Attempted to remove non-existing token: %s",
-                                binder);
-                        return;
-                    }
-
-                    token.removeAllWindowsIfPossible();
-                }
-                WindowManagerService.this.removeWindowToken(binder, displayId);
-            }
+        public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+                int displayId) {
+            WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit,
+                    displayId);
         }
 
         @Override
@@ -7900,30 +7887,37 @@
         }
 
         @Override
-        public String getImeControlTargetNameForLogging(int displayId) {
+        public ImeTargetInfo onToggleImeRequested(boolean show, IBinder focusedToken,
+                IBinder requestToken, int displayId) {
+            final String focusedWindowName;
+            final String requestWindowName;
+            final String imeControlTargetName;
+            final String imeLayerTargetName;
             synchronized (mGlobalLock) {
+                final WindowState focusedWin = mWindowMap.get(focusedToken);
+                focusedWindowName = focusedWin != null ? focusedWin.getName() : "null";
+                final WindowState requestWin = mWindowMap.get(requestToken);
+                requestWindowName = requestWin != null ? requestWin.getName() : "null";
                 final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc == null) {
-                    return null;
+                if (dc != null) {
+                    final InsetsControlTarget controlTarget = dc.getImeTarget(IME_TARGET_CONTROL);
+                    if (controlTarget != null) {
+                        final WindowState w = InsetsControlTarget.asWindowOrNull(controlTarget);
+                        imeControlTargetName = w != null ? w.getName() : controlTarget.toString();
+                    } else {
+                        imeControlTargetName = "null";
+                    }
+                    final InsetsControlTarget target = dc.getImeTarget(IME_TARGET_LAYERING);
+                    imeLayerTargetName = target != null ? target.getWindow().getName() : "null";
+                    if (show) {
+                        dc.onShowImeRequested();
+                    }
+                } else {
+                    imeControlTargetName = imeLayerTargetName = "no-display";
                 }
-                final InsetsControlTarget target = dc.getImeTarget(IME_TARGET_CONTROL);
-                if (target == null) {
-                    return null;
-                }
-                final WindowState win = target.getWindow();
-                return win != null ? win.getName() : target.toString();
             }
-        }
-
-        @Override
-        public String getImeTargetNameForLogging(int displayId) {
-            synchronized (mGlobalLock) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc == null || dc.getImeTarget(IME_TARGET_LAYERING) == null) {
-                    return null;
-                }
-                return dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getName();
-            }
+            return new ImeTargetInfo(focusedWindowName, requestWindowName, imeControlTargetName,
+                    imeLayerTargetName);
         }
 
         @Override
@@ -8124,9 +8118,8 @@
             boolean animateStarting = false;
             while (timeoutRemaining > 0) {
                 // Waiting until all starting windows has finished animating.
-                animateStarting = mRoot.forAllActivities(a -> {
-                    return a.hasStartingWindow();
-                });
+                animateStarting = !mAtmService.getTransitionController().isShellTransitionsEnabled()
+                        && mRoot.forAllActivities(ActivityRecord::hasStartingWindow);
                 boolean isAnimating = mAnimator.isAnimationScheduled()
                         || mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL)
                         || animateStarting;
@@ -8249,7 +8242,7 @@
         }
 
         updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
-                name, applicationHandle, flags, privateFlags, type, null /* region */);
+                name, applicationHandle, flags, privateFlags, type, null /* region */, window);
 
         clientChannel.copyTo(outInputChannel);
     }
@@ -8257,13 +8250,16 @@
     private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
                                     int displayId, SurfaceControl surface, String name,
                                     InputApplicationHandle applicationHandle, int flags,
-                                    int privateFlags, int type, Region region) {
+                                    int privateFlags, int type, Region region, IWindow window) {
         InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
         h.token = channelToken;
+        h.setWindowToken(window);
         h.name = name;
 
+        flags = DisplayPolicy.sanitizeFlagSlippery(flags, privateFlags, name);
+
         final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE
-                | LayoutParams.FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE);
+                | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE);
         h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
         h.layoutParamsType = type;
         h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
@@ -8315,7 +8311,7 @@
         }
 
         updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
-                applicationHandle, flags, privateFlags, win.mWindowType, region);
+                applicationHandle, flags, privateFlags, win.mWindowType, region, win.mClient);
     }
 
     /** Return whether layer tracing is enabled */
@@ -8644,8 +8640,9 @@
             if (imeTargetWindowTask == null) {
                 return false;
             }
-            final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId,
-                    false /* isLowResolution */);
+            final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
+                    imeTargetWindowTask.mUserId, false /* isLowResolution */,
+                    false /* restoreFromDisk */);
             return snapshot != null && snapshot.hasImeSurface();
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index d5965494..1d1cb70 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -24,6 +24,7 @@
 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
 
+import android.content.res.Resources.NotFoundException;
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -606,7 +607,7 @@
             return -1;
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset' or aspect ratio should be provided as an argument " + e);
+                    "Error: aspect ratio should be provided as an argument " + e);
             return -1;
         }
         synchronized (mInternal.mGlobalLock) {
@@ -625,7 +626,7 @@
             return -1;
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset' or corners radius should be provided as an argument " + e);
+                    "Error: corners radius should be provided as an argument " + e);
             return -1;
         }
         synchronized (mInternal.mGlobalLock) {
@@ -653,13 +654,13 @@
                     break;
                 default:
                     getErrPrintWriter().println(
-                            "Error: 'reset', 'solid_color', 'app_color_background' or "
+                            "Error: 'solid_color', 'app_color_background' or "
                             + "'wallpaper' should be provided as an argument");
                     return -1;
             }
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset', 'solid_color', 'app_color_background' or "
+                    "Error: 'solid_color', 'app_color_background' or "
                         + "'wallpaper' should be provided as an argument" + e);
             return -1;
         }
@@ -669,6 +670,24 @@
         return 0;
     }
 
+    private int runSetLetterboxBackgroundColorResource(PrintWriter pw) throws RemoteException {
+        final int colorId;
+        try {
+            String arg = getNextArgRequired();
+            colorId = mInternal.mContext.getResources()
+                    .getIdentifier(arg, "color", "com.android.internal");
+        } catch (NotFoundException e) {
+            getErrPrintWriter().println(
+                    "Error: color in '@android:color/resource_name' format should be provided as "
+                            + "an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxBackgroundColorResourceId(colorId);
+        }
+        return 0;
+    }
+
     private int runSetLetterboxBackgroundColor(PrintWriter pw) throws RemoteException {
         final Color color;
         try {
@@ -676,7 +695,7 @@
             color = Color.valueOf(Color.parseColor(arg));
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset' or color in #RRGGBB format should be provided as "
+                    "Error: color in #RRGGBB format should be provided as "
                             + "an argument " + e);
             return -1;
         }
@@ -697,7 +716,7 @@
             return -1;
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset' or blur radius should be provided as an argument " + e);
+                    "Error: blur radius should be provided as an argument " + e);
             return -1;
         }
         synchronized (mInternal.mGlobalLock) {
@@ -717,7 +736,7 @@
             return -1;
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset' or alpha should be provided as an argument " + e);
+                    "Error: alpha should be provided as an argument " + e);
             return -1;
         }
         synchronized (mInternal.mGlobalLock) {
@@ -736,7 +755,7 @@
             return -1;
         } catch (IllegalArgumentException  e) {
             getErrPrintWriter().println(
-                    "Error: 'reset' or multiplier should be provided as an argument " + e);
+                    "Error: multiplier should be provided as an argument " + e);
             return -1;
         }
         synchronized (mInternal.mGlobalLock) {
@@ -764,6 +783,9 @@
                 case "--backgroundColor":
                     runSetLetterboxBackgroundColor(pw);
                     break;
+                case "--backgroundColorResource":
+                    runSetLetterboxBackgroundColorResource(pw);
+                    break;
                 case "--wallpaperBlurRadius":
                     runSetLetterboxBackgroundWallpaperBlurRadius(pw);
                     break;
@@ -1031,6 +1053,11 @@
         pw.println("        is 'solid-color'. Use (set)get-letterbox-style to check and control");
         pw.println("        letterbox background type. See Color#parseColor for allowed color");
         pw.println("        formats (#RRGGBB and some colors by name, e.g. magenta or olive).");
+        pw.println("      --backgroundColorResource resource_name");
+        pw.println("        Color resource name of letterbox background which is used when");
+        pw.println("        background type is 'solid-color'. Use (set)get-letterbox-style to");
+        pw.println("        check and control background type. Parameter is a color resource");
+        pw.println("        name, for example, @android:color/system_accent2_50.");
         pw.println("      --wallpaperBlurRadius radius");
         pw.println("        Blur radius for 'wallpaper' letterbox background. If radius <= 0");
         pw.println("        both it and R.dimen.config_letterboxBackgroundWallpaperBlurRadius");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index b5d98a6..8bcd62d 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -56,6 +56,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
+import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -274,8 +275,6 @@
                 syncId = startSyncWithOrganizer(callback);
                 applyTransaction(t, syncId, null /* transition */, caller);
                 setSyncReady(syncId);
-                mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
-                        .executeAppTransition();
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -322,6 +321,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 +411,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 +433,7 @@
                 mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
             }
         } finally {
+            mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
             mService.continueWindowLayout();
         }
     }
@@ -472,7 +474,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;
     }
@@ -641,18 +651,10 @@
                     options = activityOptions.toBundle();
                 }
 
-                int res = mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
+                mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
                         hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
                         hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
                         null /* requiredPermission */, options);
-                if (res != ActivityManager.START_SUCCESS
-                        && res != ActivityManager.START_TASK_TO_FRONT) {
-                    if (!mTransitionController.isShellTransitionsEnabled()) {
-                        final DisplayContent dc =
-                                mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
-                        dc.cancelAppTransition();
-                    }
-                }
                 break;
             case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
                 final TaskFragmentCreationParams taskFragmentCreationOptions =
@@ -687,10 +689,9 @@
                         .startActivityInTaskFragment(tf, activityIntent, activityOptions,
                                 hop.getCallingActivity());
                 if (!isStartResultSuccessful(result)) {
-                    final Throwable exception =
-                            new ActivityNotFoundException("start activity in taskFragment failed");
                     sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
-                            errorCallbackToken, exception);
+                            errorCallbackToken,
+                            convertStartFailureToThrowable(result, activityIntent));
                 }
                 break;
             case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
@@ -730,6 +731,21 @@
                     break;
                 }
                 tf1.setAdjacentTaskFragment(tf2);
+
+                final Bundle bundle = hop.getLaunchOptions();
+                final WindowContainerTransaction.TaskFragmentAdjacentOptions adjacentOptions =
+                        bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentOptions(
+                                bundle) : null;
+                if (adjacentOptions == null) {
+                    break;
+                }
+
+                tf1.setDelayLastActivityRemoval(
+                        adjacentOptions.isDelayPrimaryLastActivityRemoval());
+                if (tf2 != null) {
+                    tf2.setDelayLastActivityRemoval(
+                            adjacentOptions.isDelaySecondaryLastActivityRemoval());
+                }
                 break;
         }
         return effects;
@@ -1171,7 +1187,7 @@
             return;
         }
         mLaunchTaskFragments.removeAt(index);
-        taskFragment.removeImmediately();
+        taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
     }
 
     @Nullable
@@ -1197,4 +1213,21 @@
         mService.mTaskFragmentOrganizerController
                 .onTaskFragmentError(organizer, errorCallbackToken, exception);
     }
+
+    private Throwable convertStartFailureToThrowable(int result, Intent intent) {
+        switch (result) {
+            case ActivityManager.START_INTENT_NOT_RESOLVED:
+            case ActivityManager.START_CLASS_NOT_FOUND:
+                return new ActivityNotFoundException("No Activity found to handle " + intent);
+            case ActivityManager.START_PERMISSION_DENIED:
+                return new SecurityException("Permission denied and not allowed to start activity "
+                        + intent);
+            case ActivityManager.START_CANCELED:
+                return new AndroidRuntimeException("Activity could not be started for " + intent
+                        + " with error code : " + result);
+            default:
+                return new AndroidRuntimeException("Start activity failed with error code : "
+                        + result + " when starting " + intent);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index 0ded8fb..a967ea8 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -68,7 +68,7 @@
     private static final String KEY_ROTATION_MEMORIZATION_TIMEOUT =
             "rotation_memorization_timeout_millis";
     private static final long DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS = 700L;
-    private static final long DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS = 10_000L; // 10 seconds
+    private static final long DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS = 3_000L; // 3 seconds
 
     private Handler mHandler;
     private SensorManager mSensorManager;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 65b065a..056e17d9 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -730,11 +730,14 @@
             canUpdate = true;
         }
 
-        // Compare the z-order of ActivityStacks if both activities landed on same display.
-        if (display == topDisplay
-                && mPreQTopResumedActivity.getRootTask().compareTo(
-                        activity.getRootTask()) <= 0) {
-            canUpdate = true;
+        // Update the topmost activity if the activity has higher z-order than the current
+        // top-resumed activity.
+        if (!canUpdate) {
+            final ActivityRecord ar = topDisplay.getActivity(r -> r == activity,
+                    true /* traverseTopToBottom */, mPreQTopResumedActivity);
+            if (ar != null && ar != mPreQTopResumedActivity) {
+                canUpdate = true;
+            }
         }
 
         if (canUpdate) {
@@ -945,7 +948,7 @@
                 final int displayId = r.getDisplayId();
                 final Context c = root.getDisplayUiContext(displayId);
 
-                if (r.mVisibleRequested && !displayContexts.contains(c)) {
+                if (c != null && r.mVisibleRequested && !displayContexts.contains(c)) {
                     displayContexts.add(c);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bee8bda..22db297 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -107,15 +107,17 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
@@ -153,8 +155,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
@@ -2220,11 +2220,18 @@
         }
     }
 
-    boolean onSetAppExiting() {
+    boolean onSetAppExiting(boolean animateExit) {
         final DisplayContent displayContent = getDisplayContent();
         boolean changed = false;
 
-        if (isVisibleNow()) {
+        if (!animateExit) {
+            // Hide the window permanently if no window exist animation is performed, so we can
+            // avoid the window surface becoming visible again unexpectedly during the next
+            // relayout.
+            mPermanentlyHidden = true;
+            hide(false /* doAnimation */, false /* requestAnim */);
+        }
+        if (isVisibleNow() && animateExit) {
             mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
             if (mWmService.mAccessibilityController != null) {
                 mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT);
@@ -2237,7 +2244,7 @@
 
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowState c = mChildren.get(i);
-            changed |= c.onSetAppExiting();
+            changed |= c.onSetAppExiting(animateExit);
         }
 
         return changed;
@@ -3978,7 +3985,7 @@
      * Called when the insets state changed.
      */
     void notifyInsetsChanged() {
-        ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ", this);
+        ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsChanged for %s ", this);
         try {
             mClient.insetsChanged(getCompatInsetsState(),
                     hasMoved(),
@@ -3990,7 +3997,7 @@
 
     @Override
     public void notifyInsetsControlChanged() {
-        ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this);
+        ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsControlChanged for %s ", this);
         if (mAppDied || mRemoved) {
             return;
         }
@@ -5952,9 +5959,9 @@
         outSurfaceInsets.set(getAttrs().surfaceInsets);
         final InsetsState state = getInsetsStateWithVisibilityOverride();
         outInsets.set(state.calculateInsets(outFrame, systemBars(),
-                false /* ignoreVisibility */));
+                false /* ignoreVisibility */).toRect());
         outStableInsets.set(state.calculateInsets(outFrame, systemBars(),
-                true /* ignoreVisibility */));
+                true /* ignoreVisibility */).toRect());
     }
 
     void setViewVisibility(int viewVisibility) {
@@ -5974,7 +5981,7 @@
         // since a generic WindowContainer only needs to wait for its
         // children to finish and is immediately ready from its own
         // perspective but at the WindowState level we need to wait for ourselves
-        // to draw even if the children draw first our don't need to sync, so we start
+        // to draw even if the children draw first or don't need to sync, so we start
         // in WAITING state rather than READY.
         mSyncState = SYNC_STATE_WAITING_FOR_DRAW;
         requestRedrawForSync();
@@ -5985,6 +5992,16 @@
         return true;
     }
 
+    @Override
+    boolean isSyncFinished() {
+        if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility == View.GONE) {
+            // Don't wait for GONE windows. However, we don't alter the state in case the window
+            // becomes un-gone while the syncset is still active.
+            return true;
+        }
+        return super.isSyncFinished();
+    }
+
     boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
         if (mOrientationChangeRedrawRequestTime > 0) {
             final long duration =
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 8094196..f25706a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -41,7 +41,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 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.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
 import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
@@ -71,7 +70,6 @@
  **/
 class WindowStateAnimator {
     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
-    static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
     static final int PRESERVED_SURFACE_LAYER = 1;
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index fa32be3..ad351f0 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -26,6 +26,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -239,7 +240,7 @@
         }
     }
 
-    void setExiting() {
+    void setExiting(boolean animateExit) {
         if (isEmpty()) {
             super.removeImmediately();
             return;
@@ -254,11 +255,12 @@
 
         final int count = mChildren.size();
         boolean changed = false;
-        final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
+        final boolean delayed = isAnimating(TRANSITION | PARENTS)
+                || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit);
 
         for (int i = 0; i < count; i++) {
             final WindowState win = mChildren.get(i);
-            changed |= win.onSetAppExiting();
+            changed |= win.onSetAppExiting(animateExit);
         }
 
         final ActivityRecord app = asActivityRecord();
@@ -360,7 +362,7 @@
     @Override
     void removeImmediately() {
         if (mDisplayContent != null) {
-            mDisplayContent.removeWindowToken(token);
+            mDisplayContent.removeWindowToken(token, true /* animateExit */);
         }
         // Needs to occur after the token is removed from the display above to avoid attempt at
         // duplicate removal of this window container from it's parent.
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index ab4f1f6..4e4a5c3 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,10 +175,10 @@
         "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",
+        "android.system.suspend-V1-ndk",
         "service.incremental",
     ],
 
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index a94ad4a..bb9740b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -337,7 +337,7 @@
     void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override;
     bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, int32_t injectorUid) override;
     void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
-    void setPointerCapture(bool enabled) override;
+    void setPointerCapture(const PointerCaptureRequest& request) override;
     void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
 
     /* --- PointerControllerPolicyInterface implementation --- */
@@ -372,8 +372,8 @@
         // Show touches feature enable/disable.
         bool showTouches;
 
-        // Pointer capture feature enable/disable.
-        bool pointerCapture;
+        // The latest request to enable or disable Pointer Capture.
+        PointerCaptureRequest pointerCaptureRequest;
 
         // Sprite controller singleton, created on first use.
         sp<SpriteController> spriteController;
@@ -417,7 +417,6 @@
         mLocked.pointerSpeed = 0;
         mLocked.pointerGesturesEnabled = true;
         mLocked.showTouches = false;
-        mLocked.pointerCapture = false;
         mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
     }
     mInteractive = true;
@@ -446,7 +445,9 @@
         dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n",
                 toString(mLocked.pointerGesturesEnabled));
         dump += StringPrintf(INDENT "Show Touches: %s\n", toString(mLocked.showTouches));
-        dump += StringPrintf(INDENT "Pointer Capture Enabled: %s\n", toString(mLocked.pointerCapture));
+        dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
+                             mLocked.pointerCaptureRequest.enable ? "Enabled" : "Disabled",
+                             mLocked.pointerCaptureRequest.seq);
     }
     dump += "\n";
 
@@ -634,7 +635,7 @@
 
         outConfig->showTouches = mLocked.showTouches;
 
-        outConfig->pointerCapture = mLocked.pointerCapture;
+        outConfig->pointerCaptureRequest = mLocked.pointerCaptureRequest;
 
         outConfig->setDisplayViewports(mLocked.viewports);
 
@@ -1383,16 +1384,16 @@
     checkAndClearExceptionFromCallback(env, "onPointerDownOutsideFocus");
 }
 
-void NativeInputManager::setPointerCapture(bool enabled) {
+void NativeInputManager::setPointerCapture(const PointerCaptureRequest& request) {
     { // acquire lock
         AutoMutex _l(mLock);
 
-        if (mLocked.pointerCapture == enabled) {
+        if (mLocked.pointerCaptureRequest == request) {
             return;
         }
 
-        ALOGV("%s pointer capture.", enabled ? "Enabling" : "Disabling");
-        mLocked.pointerCapture = enabled;
+        ALOGV("%s pointer capture.", request.enable ? "Enabling" : "Disabling");
+        mLocked.pointerCaptureRequest = request;
     } // release lock
 
     mInputManager->getReader()->requestRefreshConfiguration(
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index ae7ea3c..7fea547 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -18,11 +18,12 @@
 
 //#define LOG_NDEBUG 0
 
+#include <aidl/android/system/suspend/ISystemSuspend.h>
+#include <aidl/android/system/suspend/IWakeLock.h>
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
-#include <android/system/suspend/1.0/ISystemSuspend.h>
 #include <android/system/suspend/ISuspendControlService.h>
 #include <android/system/suspend/internal/ISuspendControlServiceInternal.h>
 #include <nativehelper/JNIHelp.h>
@@ -34,6 +35,7 @@
 #include <limits.h>
 
 #include <android-base/chrono_utils.h>
+#include <android/binder_manager.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
 #include <binder/IServiceManager.h>
@@ -41,20 +43,20 @@
 #include <hardware/power.h>
 #include <hardware_legacy/power.h>
 #include <hidl/ServiceManagement.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/misc.h>
-#include <utils/String8.h>
-#include <utils/Log.h>
 
 #include "com_android_server_power_PowerManagerService.h"
 
+using aidl::android::system::suspend::ISystemSuspend;
+using aidl::android::system::suspend::IWakeLock;
+using aidl::android::system::suspend::WakeLockType;
 using android::String8;
 using android::hardware::power::Boost;
 using android::hardware::power::Mode;
 using android::system::suspend::ISuspendControlService;
-using android::system::suspend::V1_0::ISystemSuspend;
-using android::system::suspend::V1_0::IWakeLock;
-using android::system::suspend::V1_0::WakeLockType;
 using IPowerV1_1 = android::hardware::power::V1_1::IPower;
 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
 using IPowerAidl = android::hardware::power::IPower;
@@ -133,20 +135,21 @@
     }
 }
 
-static sp<ISystemSuspend> gSuspendHal = nullptr;
+static std::shared_ptr<ISystemSuspend> gSuspendHal = nullptr;
 static sp<ISuspendControlService> gSuspendControl = nullptr;
 static sp<system::suspend::internal::ISuspendControlServiceInternal> gSuspendControlInternal =
         nullptr;
-static sp<IWakeLock> gSuspendBlocker = nullptr;
+static std::shared_ptr<IWakeLock> gSuspendBlocker = nullptr;
 static std::mutex gSuspendMutex;
 
 // Assume SystemSuspend HAL is always alive.
 // TODO: Force device to restart if SystemSuspend HAL dies.
-sp<ISystemSuspend> getSuspendHal() {
+std::shared_ptr<ISystemSuspend> getSuspendHal() {
     static std::once_flag suspendHalFlag;
-    std::call_once(suspendHalFlag, [](){
-        ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, "default");
-        gSuspendHal = ISystemSuspend::getService();
+    std::call_once(suspendHalFlag, []() {
+        const std::string suspendInstance = std::string() + ISystemSuspend::descriptor + "/default";
+        gSuspendHal = ISystemSuspend::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(suspendInstance.c_str())));
         assert(gSuspendHal != nullptr);
     });
     return gSuspendHal;
@@ -184,7 +187,7 @@
         std::lock_guard<std::mutex> lock(gSuspendMutex);
         if (gSuspendBlocker) {
             gSuspendBlocker->release();
-            gSuspendBlocker.clear();
+            gSuspendBlocker = nullptr;
         }
     }
 }
@@ -192,9 +195,10 @@
 void disableAutoSuspend() {
     std::lock_guard<std::mutex> lock(gSuspendMutex);
     if (!gSuspendBlocker) {
-        sp<ISystemSuspend> suspendHal = getSuspendHal();
-        gSuspendBlocker = suspendHal->acquireWakeLock(WakeLockType::PARTIAL,
-                "PowerManager.SuspendLockout");
+        std::shared_ptr<ISystemSuspend> suspendHal = getSuspendHal();
+        suspendHal->acquireWakeLock(WakeLockType::PARTIAL, "PowerManager.SuspendLockout",
+                                    &gSuspendBlocker);
+        assert(gSuspendBlocker != nullptr);
     }
 }
 
diff --git a/services/core/lint-baseline.xml b/services/core/lint-baseline.xml
new file mode 100644
index 0000000..c5b0549
--- /dev/null
+++ b/services/core/lint-baseline.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="            return Settings.Secure.getInt(context.getContentResolver(),"
+        errorLine2="                   ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java"
+            line="1106"
+            column="20"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="            return Settings.Secure.getInt(context.getContentResolver(),"
+        errorLine2="                   ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java"
+            line="1111"
+            column="20"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
+        errorLine1="            return Settings.Secure.getString(mContentResolver, mKey);"
+        errorLine2="                                   ~~~~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/CertBlacklister.java"
+            line="73"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="        }"
+        errorLine2="      ^">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/clipboard/ClipboardService.java"
+            line="973"
+            column="7"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="            boolean accessibilityEnabled = Settings.Secure.getInt(cr,"
+        errorLine2="                                                           ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/DockObserver.java"
+            line="176"
+            column="60"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
+        errorLine1="            String mediaButtonReceiverInfo = Settings.Secure.getString(mContentResolver,"
+        errorLine2="                                             ~~~~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/media/MediaSessionService.java"
+            line="928"
+            column="46"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="            final boolean isSecureFrpEnabled ="
+        errorLine2="                                   ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java"
+            line="1959"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="    private int getUnknownSourcesSettings() {"
+        errorLine2="                                      ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java"
+            line="16741"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
+        errorLine1="            String inputMethodComponent = Settings.Secure.getString(mContext.getContentResolver(),"
+        errorLine2="                                  ~~~~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/SensorPrivacyService.java"
+            line="489"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
+        errorLine1="            return Settings.Secure.getString(getContentResolverAsUser(userId), key);"
+        errorLine2="           ~~~~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java"
+            line="1994"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="            return Settings.Secure.getInt(getContentResolverAsUser(userId), key, def);"
+        errorLine2="           ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java"
+            line="2001"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="                        if (Settings.Secure.getInt(mContext.getContentResolver(),"
+        errorLine2="                                            ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java"
+            line="980"
+            column="45"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="                &amp;&amp; Settings.Secure.getInt(mContext.getContentResolver(),"
+        errorLine2="                                   ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java"
+            line="1442"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="                &amp;&amp; Settings.Secure.getInt(mContext.getContentResolver(),"
+        errorLine2="                                   ~~~~~~">
+        <location
+            file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java"
+            line="1444"
+            column="36"/>
+    </issue>
+
+</issues>
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index d43cf3f..6a50d38 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -14,7 +14,6 @@
     package_name: "com.android.server.pm.permission.configfile",
 }
 
-
 xsd_config {
     name: "platform-compat-config",
     srcs: ["platform-compat/config/platform-compat-config.xsd"],
@@ -42,6 +41,7 @@
     srcs: ["display-layout-config/display-layout-config.xsd"],
     api_dir: "display-layout-config/schema",
     package_name: "com.android.server.display.config.layout",
+    boolean_getter: true,
 }
 
 xsd_config {
diff --git a/services/core/xsd/device-state-config/device-state-config.xsd b/services/core/xsd/device-state-config/device-state-config.xsd
index 94a398f..86f4176 100644
--- a/services/core/xsd/device-state-config/device-state-config.xsd
+++ b/services/core/xsd/device-state-config/device-state-config.xsd
@@ -40,10 +40,19 @@
             <xs:element name="name" type="xs:string" minOccurs="0">
                 <xs:annotation name="nullable" />
             </xs:element>
+            <xs:element name="flags" type="flags" />
             <xs:element name="conditions" type="conditions" />
         </xs:sequence>
     </xs:complexType>
 
+    <xs:complexType name="flags">
+        <xs:sequence>
+            <xs:element name="flag" type="xs:string" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation name="nullable" />
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
     <xs:complexType name="conditions">
         <xs:sequence>
             <xs:element name="lid-switch" type="lidSwitchCondition" minOccurs="0">
diff --git a/services/core/xsd/device-state-config/schema/current.txt b/services/core/xsd/device-state-config/schema/current.txt
index 08fccf8..a98d4e5 100644
--- a/services/core/xsd/device-state-config/schema/current.txt
+++ b/services/core/xsd/device-state-config/schema/current.txt
@@ -11,9 +11,11 @@
   public class DeviceState {
     ctor public DeviceState();
     method public com.android.server.policy.devicestate.config.Conditions getConditions();
+    method public com.android.server.policy.devicestate.config.Flags getFlags();
     method public java.math.BigInteger getIdentifier();
     method @Nullable public String getName();
     method public void setConditions(com.android.server.policy.devicestate.config.Conditions);
+    method public void setFlags(com.android.server.policy.devicestate.config.Flags);
     method public void setIdentifier(java.math.BigInteger);
     method public void setName(@Nullable String);
   }
@@ -23,6 +25,11 @@
     method public java.util.List<com.android.server.policy.devicestate.config.DeviceState> getDeviceState();
   }
 
+  public class Flags {
+    ctor public Flags();
+    method @Nullable public java.util.List<java.lang.String> getFlag();
+  }
+
   public class LidSwitchCondition {
     ctor public LidSwitchCondition();
     method public boolean getOpen();
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index c542c0d..e14139a 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -52,6 +52,6 @@
             <xs:element name="address" type="xs:nonNegativeInteger"/>
         </xs:sequence>
         <xs:attribute name="enabled" type="xs:boolean" use="optional" />
-        <xs:attribute name="isDefault" type="xs:boolean" use="optional" />
+        <xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" />
     </xs:complexType>
 </xs:schema>
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index 8171885..f391575 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -4,11 +4,11 @@
   public class Display {
     ctor public Display();
     method public java.math.BigInteger getAddress();
-    method public boolean getEnabled();
-    method public boolean getIsDefault();
+    method public boolean isDefaultDisplay();
+    method public boolean isEnabled();
     method public void setAddress(java.math.BigInteger);
+    method public void setDefaultDisplay(boolean);
     method public void setEnabled(boolean);
-    method public void setIsDefault(boolean);
   }
 
   public class Layout {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index be8b21c..a9ddd35 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -648,6 +648,7 @@
 
     private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl();
     private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl();
+    private final Object mESIDInitilizationLock = new Object();
     private EnterpriseSpecificIdCalculator mEsidCalculator;
 
     /**
@@ -3126,10 +3127,6 @@
                 factoryResetIfDelayedEarlier();
 
                 ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
-
-                // This is constructed here as EnterpriseSpecificIdCalculator depends on telephony
-                // and wifi service and these services are only fully available at this stage.
-                mEsidCalculator = mInjector.newEnterpriseSpecificIdCalculator();
                 break;
         }
     }
@@ -3813,17 +3810,6 @@
         }
     }
 
-    @Override
-    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
-        Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()),
-                String.format(NOT_SYSTEM_CALLER_MSG, "query separate challenge support"));
-
-        ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
-        // Profile challenge is supported on N or newer release.
-        return profileOwner != null &&
-                getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
-    }
-
     private boolean canSetPasswordQualityOnParent(String packageName, final CallerIdentity caller) {
         return !mInjector.isChangeEnabled(
                 PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT, packageName, caller.getUserId())
@@ -10124,7 +10110,7 @@
     }
 
     @Override
-    public boolean setPermittedAccessibilityServices(ComponentName who, List packageList) {
+    public boolean setPermittedAccessibilityServices(ComponentName who, List<String> packageList) {
         if (!mHasFeature) {
             return false;
         }
@@ -10176,7 +10162,7 @@
     }
 
     @Override
-    public List getPermittedAccessibilityServices(ComponentName who) {
+    public List<String> getPermittedAccessibilityServices(ComponentName who) {
         if (!mHasFeature) {
             return null;
         }
@@ -10191,7 +10177,7 @@
     }
 
     @Override
-    public List getPermittedAccessibilityServicesForUser(int userId) {
+    public List<String> getPermittedAccessibilityServicesForUser(int userId) {
         if (!mHasFeature) {
             return null;
         }
@@ -10277,7 +10263,7 @@
     }
 
     @Override
-    public boolean setPermittedInputMethods(ComponentName who, List packageList,
+    public boolean setPermittedInputMethods(ComponentName who, List<String> packageList,
             boolean calledOnParentInstance) {
         if (!mHasFeature) {
             return false;
@@ -10341,7 +10327,8 @@
     }
 
     @Override
-    public List getPermittedInputMethods(ComponentName who, boolean calledOnParentInstance) {
+    public List<String> getPermittedInputMethods(ComponentName who,
+            boolean calledOnParentInstance) {
         if (!mHasFeature) {
             return null;
         }
@@ -10362,7 +10349,7 @@
     }
 
     @Override
-    public List getPermittedInputMethodsForCurrentUser() {
+    public List<String> getPermittedInputMethodsForCurrentUser() {
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(canManageUsers(caller));
 
@@ -11605,14 +11592,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;
@@ -16927,8 +16911,6 @@
     @Override
     public void setOrganizationIdForUser(
             @NonNull String callerPackage, @NonNull String organizationId, int userId) {
-        Preconditions.checkState(mEsidCalculator != null,
-                "setOrganizationIdForUser can't be called before boot phase completion");
         if (!mHasFeature) {
             return;
         }
@@ -16944,6 +16926,14 @@
 
         Slogf.i(LOG_TAG, "Setting Enterprise ID to %s for user %d", organizationId, userId);
 
+        synchronized (mESIDInitilizationLock) {
+            if (mEsidCalculator == null) {
+                mInjector.binderWithCleanCallingIdentity(() -> {
+                    mEsidCalculator = mInjector.newEnterpriseSpecificIdCalculator();
+                });
+            }
+        }
+
         final String ownerPackage;
         synchronized (getLockObject()) {
             final ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
@@ -16961,13 +16951,11 @@
                     "The organization ID has been previously set to a different value and cannot "
                             + "be changed");
             final String dpcPackage = owner.info.getPackageName();
-            mInjector.binderWithCleanCallingIdentity(() -> {
-                final String esid = mEsidCalculator.calculateEnterpriseId(dpcPackage,
-                        organizationId);
-                owner.mOrganizationId = organizationId;
-                owner.mEnrollmentSpecificId = esid;
-                saveSettingsLocked(userId);
-            });
+            final String esid = mEsidCalculator.calculateEnterpriseId(dpcPackage,
+                    organizationId);
+            owner.mOrganizationId = organizationId;
+            owner.mEnrollmentSpecificId = esid;
+            saveSettingsLocked(userId);
         }
 
         DevicePolicyEventLogger
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
index 29091ce..df7f308 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -51,19 +51,13 @@
 
     EnterpriseSpecificIdCalculator(Context context) {
         TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
-        if (telephonyService != null) {
-            mImei = telephonyService.getImei(0);
-            mMeid = telephonyService.getMeid(0);
-        } else {
-            mImei = "";
-            mMeid = "";
-        }
+        Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
+        mImei = telephonyService.getImei(0);
+        mMeid = telephonyService.getMeid(0);
         mSerialNumber = Build.getSerial();
         WifiManager wifiManager = context.getSystemService(WifiManager.class);
-        String[] macAddresses = null;
-        if (wifiManager != null) {
-            macAddresses = wifiManager.getFactoryMacAddresses();
-        }
+        Preconditions.checkState(wifiManager != null, "Unable to access WiFi service");
+        final String[] macAddresses = wifiManager.getFactoryMacAddresses();
         if (macAddresses == null || macAddresses.length == 0) {
             mMacAddress = "";
         } else {
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 0bd737b..957d7c3 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -65,7 +65,6 @@
         "libincremental_manager_aidl-cpp",
         "libprotobuf-cpp-lite",
         "service.incremental.proto",
-        "libutils",
         "libvold_binder",
         "libc++fs",
         "libziparchive_for_incfs",
@@ -78,6 +77,7 @@
         "libincfs",
         "liblog",
         "libpermission",
+        "libutils",
         "libz",
     ],
 }
diff --git a/services/incremental/TEST_MAPPING b/services/incremental/TEST_MAPPING
index 6aa8a93..f2ad068 100644
--- a/services/incremental/TEST_MAPPING
+++ b/services/incremental/TEST_MAPPING
@@ -1,20 +1,6 @@
 {
   "presubmit": [
     {
-      "name": "CtsContentTestCases",
-      "options": [
-        {
-          "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
-        },
-        {
-          "include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
-        },
-        {
-          "include-filter": "android.content.pm.cts.ChecksumsTest"
-        }
-      ]
-    },
-    {
       "name": "CtsPackageManagerStatsHostTestCases",
       "options": [
         {
@@ -29,6 +15,20 @@
   "presubmit-large": [
     {
       "name": "CtsInstalledLoadingProgressHostTests"
+    },
+    {
+      "name": "CtsContentTestCases",
+      "options": [
+        {
+          "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
+        },
+        {
+          "include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
+        },
+        {
+          "include-filter": "android.content.pm.cts.ChecksumsTest"
+        }
+      ]
     }
   ]
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0010015..aa5b209 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -302,6 +302,8 @@
             "com.android.clockwork.power.WearPowerService";
     private static final String WEAR_SIDEKICK_SERVICE_CLASS =
             "com.google.android.clockwork.sidekick.SidekickService";
+    private static final String WEAR_DISPLAYOFFLOAD_SERVICE_CLASS =
+            "com.google.android.clockwork.displayoffload.DisplayOffloadService";
     private static final String WEAR_DISPLAY_SERVICE_CLASS =
             "com.google.android.clockwork.display.WearDisplayService";
     private static final String WEAR_LEFTY_SERVICE_CLASS =
@@ -384,6 +386,8 @@
     private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";
     private static final String GAME_MANAGER_SERVICE_CLASS =
             "com.android.server.app.GameManagerService$Lifecycle";
+    private static final String UWB_APEX_SERVICE_JAR_PATH =
+            "/apex/com.android.uwb/javalib/service-uwb.jar";
     private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
 
     private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -438,7 +442,6 @@
     private static final String SYSPROP_START_UPTIME = "sys.system_server.start_uptime";
 
     private Future<?> mZygotePreload;
-    private Future<?> mBlobStoreServiceStart;
 
     private final SystemServerDumper mDumper = new SystemServerDumper();
 
@@ -1118,6 +1121,13 @@
         mSystemServiceManager.startService(LightsService.class);
         t.traceEnd();
 
+        t.traceBegin("StartDisplayOffloadService");
+        // Package manager isn't started yet; need to use SysProp not hardware feature
+        if (SystemProperties.getBoolean("config.enable_display_offload", false)) {
+            mSystemServiceManager.startService(WEAR_DISPLAYOFFLOAD_SERVICE_CLASS);
+        }
+        t.traceEnd();
+
         t.traceBegin("StartSidekickService");
         // Package manager isn't started yet; need to use SysProp not hardware feature
         if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
@@ -2077,14 +2087,11 @@
             mSystemServiceManager.startService(DockObserver.class);
             t.traceEnd();
 
-            // TODO(b/191495635): re-enable thermal observer after fixing b/191375904.
-            /*
             if (isWatch) {
                 t.traceBegin("StartThermalObserver");
                 mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
                 t.traceEnd();
             }
-            */
 
             t.traceBegin("StartWiredAccessoryManager");
             try {
@@ -2260,12 +2267,9 @@
                 t.traceEnd();
             }
 
-            mBlobStoreServiceStart = SystemServerInitThreadPool.submit(() -> {
-                final TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
-                traceLog.traceBegin(START_BLOB_STORE_SERVICE);
-                mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
-                traceLog.traceEnd();
-            }, START_BLOB_STORE_SERVICE);
+            t.traceBegin(START_BLOB_STORE_SERVICE);
+            mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
+            t.traceEnd();
 
             // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
             t.traceBegin("StartDreamManager");
@@ -2438,8 +2442,6 @@
             t.traceEnd();
         }
 
-        // TODO(b/191495635): Re-enable these services after fixing b/191375904.
-       /*
        if (isWatch) {
             // Must be started before services that depend it, e.g. WearConnectivityService
             t.traceBegin("StartWearPowerService");
@@ -2468,7 +2470,6 @@
             mSystemServiceManager.startService(WEAR_GLOBAL_ACTIONS_SERVICE_CLASS);
             t.traceEnd();
         }
-        */
 
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_SLICES_DISABLED)) {
             t.traceBegin("StartSliceManagerService");
@@ -2651,7 +2652,7 @@
 
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
             t.traceBegin("UwbService");
-            mSystemServiceManager.startService(UWB_SERVICE_CLASS);
+            mSystemServiceManager.startServiceFromJar(UWB_SERVICE_CLASS, UWB_APEX_SERVICE_JAR_PATH);
             t.traceEnd();
         }
 
@@ -2671,9 +2672,6 @@
         mSystemServiceManager.startService(APP_COMPAT_OVERRIDES_SERVICE_CLASS);
         t.traceEnd();
 
-        ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
-                START_BLOB_STORE_SERVICE);
-
         // These are needed to propagate to the runnable below.
         final NetworkManagementService networkManagementF = networkManagement;
         final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 21964dd..09a831e 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -51,7 +51,6 @@
         // classes generated by netd_aidl_interfaces-platform-java above.
         "netd_aidl_interface-V3-java",
         "networkstack-client",
-        "modules-utils-build_system",
     ],
     apex_available: [
         "com.android.wifi",
diff --git a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
index dc8c811..f584599 100644
--- a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
@@ -20,6 +20,13 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command"
+            value="pm uninstall com.android.cts.install.lib.testapp.A" />
+        <option name="teardown-command"
+            value="pm uninstall com.android.cts.install.lib.testapp.A" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.HostTest">
         <option name="jar" value="PackageManagerServiceHostTests.jar" />
     </test>
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/PackageInstallerSessionTest.kt
new file mode 100644
index 0000000..86571ab
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/PackageInstallerSessionTest.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
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import kotlin.jvm.JvmField
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class PackageInstallerSessionTest : BaseHostJUnit4Test() {
+    companion object {
+        private const val DEVICE_SIDE = "PackageManagerServiceDeviceSideTests.apk"
+    }
+
+    @Rule
+    @JvmField
+    val tempFolder = TemporaryFolder()
+
+    @Test
+    fun verify_parentSessionFail_childSessionFiles_shouldBeDestroyed() {
+        runDeviceTest("com.android.server.pm.PackageInstallerSessionTest",
+                "verify_parentSessionFail_childSessionFiles_shouldBeDestroyed")
+    }
+
+    /**
+     * Run a device side test from com.android.server.pm.test.deviceside.DeviceSide
+     *
+     * @param method the method to run
+     */
+    fun runDeviceTest(testClassName: String, method: String) {
+        val deviceSideFile = HostUtils.copyResourceToHostFile(DEVICE_SIDE, tempFolder.newFile())
+        Truth.assertThat(device.installPackage(deviceSideFile, true)).isNull()
+        runDeviceTests(device, "com.android.server.pm.test.deviceside",
+                testClassName, method)
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 7e4f0e7..53adc2f 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -32,6 +32,8 @@
     ],
     static_libs: [
         "androidx.annotation_annotation",
+        "commands-helper",
+        "cts-install-lib",
         "junit",
         "junit-params",
         "androidx.test.ext.junit",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml
index 286ad56..dd6dea7 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml
@@ -19,6 +19,8 @@
     package="com.android.server.pm.test.deviceside">
 
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
 
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/src/com/android/server/pm/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/src/com/android/server/pm/PackageInstallerSessionTest.kt
new file mode 100644
index 0000000..bdef8f1
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/src/com/android/server/pm/PackageInstallerSessionTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.Manifest
+import android.app.Instrumentation
+import android.content.Context
+import android.system.helpers.CommandsHelper
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.compatibility.common.util.AdoptShellPermissionsRule
+import com.android.compatibility.common.util.SystemUtil
+import com.android.cts.install.lib.Install
+import com.android.cts.install.lib.InstallUtils
+import com.android.cts.install.lib.LocalIntentSender
+import com.android.cts.install.lib.TestApp
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import java.io.IOException
+import kotlin.jvm.JvmField
+
+class PackageInstallerSessionTest {
+    @Rule
+    @JvmField
+    val mAdoptShellPermissionsRule = AdoptShellPermissionsRule(
+            getInstrumentation().getUiAutomation(),
+            Manifest.permission.INSTALL_PACKAGES,
+            Manifest.permission.DELETE_PACKAGES)
+
+    private val mInstrumentation: Instrumentation = getInstrumentation()
+    private var mChildSessionStageDirInfo: String? = null
+
+    /**
+     * To get all of child session IDs.
+     *
+     * @param parentSessionId the parent session id
+     * @return the array of child session IDs
+     * @throws IOException caused by opening parent session fail.
+     */
+    @Throws(IOException::class)
+    private fun getChildSessionIds(parentSessionId: Int): IntArray {
+        InstallUtils.openPackageInstallerSession(parentSessionId).use {
+            parentSession -> return parentSession.childSessionIds
+        }
+    }
+
+    private fun getSessionStageDir(sessionId: Int): String? {
+        val commandsHelper: CommandsHelper = CommandsHelper.getInstance(mInstrumentation)
+        val dumpsysForPackage: MutableList<String>? = commandsHelper
+                .executeShellCommandAndSplitOutput("dumpsys package", "\\n")
+        val pattern = Regex(" stageDir=(\\S+${sessionId}\\S+) ")
+        val matchStageDirs: ArrayList<String> = ArrayList()
+        dumpsysForPackage?.forEach { line ->
+            val matchResult: MatchResult? = pattern.find(line)
+            if (matchResult != null) {
+                val (stageDir: String) = matchResult.destructured
+                matchStageDirs.add(stageDir)
+            }
+        }
+
+        if (matchStageDirs.size > 0) {
+            return matchStageDirs[0]
+        }
+        return null
+    }
+
+    private fun getSessionStageDirInfo(sessionId: Int): String? {
+        SystemUtil.runWithShellPermissionIdentity {
+            val sessionStageDir =
+                    getSessionStageDir(sessionId) ?: return@runWithShellPermissionIdentity
+            val command = "su root ls $sessionStageDir"
+            val lines: List<String> = CommandsHelper.getInstance(mInstrumentation)
+                    .executeShellCommandAndSplitOutput(command, "\\n")
+            val sessionIdStr = sessionId.toString()
+            for (line in lines) {
+                if (line.contains(sessionIdStr)) {
+                    mChildSessionStageDirInfo = line
+                }
+            }
+        }
+        return mChildSessionStageDirInfo
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun verify_parentSessionFail_childSessionFiles_shouldBeDestroyed() {
+        val context: Context = mInstrumentation.targetContext
+        Install.single(TestApp.A3).commit()
+        val parentSessionId: Int = Install.multi(TestApp.A1).createSession()
+        val childSessionIds: IntArray = getChildSessionIds(parentSessionId)
+        val firstChildSessionId = childSessionIds[0]
+
+        val sender = LocalIntentSender()
+        try {
+            InstallUtils.openPackageInstallerSession(parentSessionId).use { session ->
+                session.commit(sender.intentSender)
+                val result = sender.result
+                InstallUtils.assertStatusFailure(result)
+            }
+        } finally {
+            context.unregisterReceiver(sender)
+        }
+
+        Truth.assertThat(getSessionStageDirInfo(firstChildSessionId)).isNull()
+    }
+}
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..64c426b
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -0,0 +1,571 @@
+/*
+ * 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.AndroidPackageUtils
+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
+import kotlin.reflect.KFunction1
+
+@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",
+        // 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::getOverlayTargetOverlayableName,
+        AndroidPackage::getPackageName,
+        AndroidPackage::getPath,
+        AndroidPackage::getPermission,
+        PackageImpl::getPrimaryCpuAbi,
+        AndroidPackage::getProcessName,
+        AndroidPackage::getRequiredAccountType,
+        AndroidPackage::getRequiresSmallestWidthDp,
+        AndroidPackage::getResizeableActivity,
+        AndroidPackage::getRestrictedAccountType,
+        AndroidPackage::getRoundIconRes,
+        PackageImpl::getSeInfo,
+        PackageImpl::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(PackageImpl::getVersionCode, 3),
+        getter(PackageImpl::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::getRequestedFeatures,
+            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/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 886b2e0..d6d5e62 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -27,7 +27,6 @@
 import android.os.Build
 import android.os.Process
 import android.util.ArraySet
-import android.util.SparseArray
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.pm.PackageSetting
 import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -332,7 +331,7 @@
                 domainSetId
             )
         ) {
-            whenever(getName()) { packageName }
+            whenever(getPackageName()) { packageName }
             whenever(getPkg()) { mockPkg(packageName) }
             whenever(this.domainSetId) { domainSetId }
             whenever(readUserState(0)) { PackageUserState() }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index 0fe3913..d67b26a 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -77,7 +77,7 @@
         }
 
         assertThat(service.queryValidVerificationPackageNames())
-                .containsExactly(pkgWithDomains.getName())
+                .containsExactly(pkgWithDomains.getPackageName())
     }
 
     @Test
@@ -104,16 +104,16 @@
             addPackages(pkgWithDomains, pkgWithoutDomains)
         }
 
-        val infoOne = service.getDomainVerificationInfo(pkgWithDomains.getName())
+        val infoOne = service.getDomainVerificationInfo(pkgWithDomains.getPackageName())
         assertThat(infoOne).isNotNull()
         assertThat(infoOne!!.identifier).isEqualTo(pkgWithDomains.domainSetId)
-        assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getName())
+        assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getPackageName())
         assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(mapOf(
                 DOMAIN_1 to DomainVerificationInfo.STATE_NO_RESPONSE,
                 DOMAIN_2 to DomainVerificationInfo.STATE_NO_RESPONSE
         ))
 
-        assertThat(service.getDomainVerificationInfo(pkgWithoutDomains.getName())).isNull()
+        assertThat(service.getDomainVerificationInfo(pkgWithoutDomains.getPackageName())).isNull()
 
         assertFailsWith(PackageManager.NameNotFoundException::class) {
             service.getDomainVerificationInfo("invalid.pkg.name")
@@ -125,7 +125,7 @@
         val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, listOf(DOMAIN_1, DOMAIN_2))
         val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, listOf(DOMAIN_3, DOMAIN_4))
 
-        val map = mutableMapOf(pkg1.getName() to pkg1, pkg2.getName() to pkg2)
+        val map = mutableMapOf(pkg1.getPackageName() to pkg1, pkg2.getPackageName() to pkg2)
         val service = makeService(map::get).apply { addPackages(pkg1, pkg2) }
 
         assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_2), 1100))
@@ -167,7 +167,7 @@
         val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, listOf(DOMAIN_1, DOMAIN_2))
         val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, listOf(DOMAIN_3, DOMAIN_4))
 
-        val map = mutableMapOf(pkg1.getName() to pkg1, pkg2.getName() to pkg2)
+        val map = mutableMapOf(pkg1.getPackageName() to pkg1, pkg2.getPackageName() to pkg2)
         val service = makeService(map::get).apply { addPackages(pkg1, pkg2) }
 
         service.setDomainVerificationLinkHandlingAllowed(PKG_ONE, false, 0)
@@ -196,9 +196,9 @@
         val pkg3 = mockPkgSetting(PKG_THREE, UUID_THREE, listOf(DOMAIN_1, DOMAIN_2))
 
         val map = mutableMapOf(
-                pkg1.getName() to pkg1,
-                pkg2.getName() to pkg2,
-                pkg3.getName() to pkg3
+                pkg1.getPackageName() to pkg1,
+                pkg2.getPackageName() to pkg2,
+                pkg3.getPackageName() to pkg3
         )
         val service = makeService(map::get).apply { addPackages(pkg1, pkg2, pkg3) }
 
@@ -248,20 +248,20 @@
             addPackages(pkgWithDomains, pkgWithoutDomains)
         }
 
-        val infoOne = service.getDomainVerificationUserState(pkgWithDomains.getName(), 0)
+        val infoOne = service.getDomainVerificationUserState(pkgWithDomains.getPackageName(), 0)
         assertThat(infoOne).isNotNull()
         assertThat(infoOne!!.identifier).isEqualTo(pkgWithDomains.domainSetId)
-        assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getName())
+        assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getPackageName())
         assertThat(infoOne.isLinkHandlingAllowed).isTrue()
         assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(mapOf(
                 DOMAIN_1 to DomainVerificationUserState.DOMAIN_STATE_NONE,
                 DOMAIN_2 to DomainVerificationUserState.DOMAIN_STATE_NONE
         ))
 
-        val infoTwo = service.getDomainVerificationUserState(pkgWithoutDomains.getName(), 0)
+        val infoTwo = service.getDomainVerificationUserState(pkgWithoutDomains.getPackageName(), 0)
         assertThat(infoTwo).isNotNull()
         assertThat(infoTwo!!.identifier).isEqualTo(pkgWithoutDomains.domainSetId)
-        assertThat(infoTwo.packageName).isEqualTo(pkgWithoutDomains.getName())
+        assertThat(infoTwo.packageName).isEqualTo(pkgWithoutDomains.getPackageName())
         assertThat(infoOne.isLinkHandlingAllowed).isTrue()
         assertThat(infoTwo.hostToStateMap).isEmpty()
 
@@ -323,43 +323,43 @@
 
         service.getOwnersForDomain(DOMAIN_1, 0).let {
             assertThat(it).containsExactly(
-                DomainOwner(pkg1.getName(), false),
-                DomainOwner(pkg2.getName(), false)
+                DomainOwner(pkg1.getPackageName(), false),
+                DomainOwner(pkg2.getPackageName(), false)
             ).inOrder()
         }
         manager0.getOwnersForDomain(DOMAIN_1).let {
             assertThat(it).containsExactly(
-                DomainOwner(pkg1.getName(), false),
-                DomainOwner(pkg2.getName(), false)
+                DomainOwner(pkg1.getPackageName(), false),
+                DomainOwner(pkg2.getPackageName(), false)
             ).inOrder()
         }
 
         service.getOwnersForDomain(DOMAIN_2, 0).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
         manager0.getOwnersForDomain(DOMAIN_2).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
 
         assertThat(service.getOwnersForDomain(DOMAIN_2, 1)).isEmpty()
         assertThat(manager1.getOwnersForDomain(DOMAIN_2)).isEmpty()
         service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 1)
         service.getOwnersForDomain(DOMAIN_2, 1).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
         manager1.getOwnersForDomain(DOMAIN_2).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
 
         // "Uninstall" the package from user 0 and ensure it's stripped from the results
         pkg1User0Enabled.set(false)
-        service.clearPackageForUser(pkg1.getName(), 0)
+        service.clearPackageForUser(pkg1.getPackageName(), 0)
 
         service.getOwnersForDomain(DOMAIN_1, 0).let {
-            assertThat(it).containsExactly(DomainOwner(pkg2.getName(), false))
+            assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), false))
         }
         manager0.getOwnersForDomain(DOMAIN_1).let {
-            assertThat(it).containsExactly(DomainOwner(pkg2.getName(), false))
+            assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), false))
         }
 
         // Domain 2 user selection gone for user 0
@@ -367,33 +367,33 @@
 
         // Domain 2 user selection still around for user 1
         service.getOwnersForDomain(DOMAIN_2, 1).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
         manager1.getOwnersForDomain(DOMAIN_2).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
 
         // Now assert for user 1 that it was unaffected by the change to user 0
         service.getOwnersForDomain(DOMAIN_1, 1).let {
             assertThat(it).containsExactly(
-                DomainOwner(pkg1.getName(), false),
-                DomainOwner(pkg2.getName(), false)
+                DomainOwner(pkg1.getPackageName(), false),
+                DomainOwner(pkg2.getPackageName(), false)
             ).inOrder()
         }
         manager1.getOwnersForDomain(DOMAIN_1).let {
             assertThat(it).containsExactly(
-                DomainOwner(pkg1.getName(), false),
-                DomainOwner(pkg2.getName(), false)
+                DomainOwner(pkg1.getPackageName(), false),
+                DomainOwner(pkg2.getPackageName(), false)
             ).inOrder()
         }
 
         service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 0)
 
         service.getOwnersForDomain(DOMAIN_2, 1).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
         manager1.getOwnersForDomain(DOMAIN_2).let {
-            assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
         }
 
         // "Reinstall" the package to user 0
@@ -406,10 +406,10 @@
         // Other package unaffected
         service.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_2), true, 0)
         service.getOwnersForDomain(DOMAIN_2, 0).let {
-            assertThat(it).containsExactly(DomainOwner(pkg2.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), true))
         }
         manager0.getOwnersForDomain(DOMAIN_2).let {
-            assertThat(it).containsExactly(DomainOwner(pkg2.getName(), true))
+            assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), true))
         }
     }
 
@@ -456,7 +456,7 @@
     }
 
     private fun makeService(vararg pkgSettings: PackageSetting) =
-            makeService { pkgName -> pkgSettings.find { pkgName == it.getName() } }
+            makeService { pkgName -> pkgSettings.find { pkgName == it.getPackageName() } }
 
     private fun makeService(pkgSettingFunction: (String) -> PackageSetting? = { null }) =
             DomainVerificationService(mockThrowOnUnmocked {
@@ -521,7 +521,7 @@
         }
 
         whenever(getPkg()) { pkg }
-        whenever(getName()) { pkgName }
+        whenever(getPackageName()) { pkgName }
         whenever(this.domainSetId) { domainSetId }
         whenever(getInstantApp(anyInt())) { false }
         whenever(firstInstallTime) { 0L }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 6c2a891..03f1124 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -81,16 +81,16 @@
     fun addPackageFirstTime() {
         val service = makeService(pkg1, pkg2)
         service.addPackage(pkg1)
-        val info = service.getInfo(pkg1.getName())
-        assertThat(info.packageName).isEqualTo(pkg1.getName())
+        val info = service.getInfo(pkg1.getPackageName())
+        assertThat(info.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(info.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(info.hostToStateMap).containsExactlyEntriesIn(mapOf(
                 DOMAIN_1 to STATE_NO_RESPONSE,
                 DOMAIN_2 to STATE_NO_RESPONSE,
         ))
 
-        val userState = service.getUserState(pkg1.getName())
-        assertThat(userState.packageName).isEqualTo(pkg1.getName())
+        val userState = service.getUserState(pkg1.getPackageName())
+        assertThat(userState.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(userState.isLinkHandlingAllowed).isEqualTo(true)
         assertThat(userState.user.identifier).isEqualTo(USER_ID)
@@ -100,7 +100,7 @@
         ))
 
         assertThat(service.queryValidVerificationPackageNames())
-                .containsExactly(pkg1.getName())
+                .containsExactly(pkg1.getPackageName())
     }
 
     @Test
@@ -109,14 +109,14 @@
         val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, SIGNATURE_TWO, isSystemApp = true)
 
         val service = makeService(
-            systemConfiguredPackageNames = ArraySet(setOf(pkg1.getName(), pkg2.getName())),
+            systemConfiguredPackageNames = ArraySet(setOf(pkg1.getPackageName(), pkg2.getPackageName())),
             pkg1, pkg2
         )
         service.addPackage(pkg1)
         service.addPackage(pkg2)
 
-        service.getInfo(pkg1.getName()).apply {
-            assertThat(packageName).isEqualTo(pkg1.getName())
+        service.getInfo(pkg1.getPackageName()).apply {
+            assertThat(packageName).isEqualTo(pkg1.getPackageName())
             assertThat(identifier).isEqualTo(pkg1.domainSetId)
             assertThat(hostToStateMap).containsExactlyEntriesIn(
                 mapOf(
@@ -126,8 +126,8 @@
             )
         }
 
-        service.getUserState(pkg1.getName()).apply {
-            assertThat(packageName).isEqualTo(pkg1.getName())
+        service.getUserState(pkg1.getPackageName()).apply {
+            assertThat(packageName).isEqualTo(pkg1.getPackageName())
             assertThat(identifier).isEqualTo(pkg1.domainSetId)
             assertThat(isLinkHandlingAllowed).isEqualTo(true)
             assertThat(user.identifier).isEqualTo(USER_ID)
@@ -139,8 +139,8 @@
             )
         }
 
-        service.getInfo(pkg2.getName()).apply {
-            assertThat(packageName).isEqualTo(pkg2.getName())
+        service.getInfo(pkg2.getPackageName()).apply {
+            assertThat(packageName).isEqualTo(pkg2.getPackageName())
             assertThat(identifier).isEqualTo(pkg2.domainSetId)
             assertThat(hostToStateMap).containsExactlyEntriesIn(
                 mapOf(
@@ -150,8 +150,8 @@
             )
         }
 
-        service.getUserState(pkg2.getName()).apply {
-            assertThat(packageName).isEqualTo(pkg2.getName())
+        service.getUserState(pkg2.getPackageName()).apply {
+            assertThat(packageName).isEqualTo(pkg2.getPackageName())
             assertThat(identifier).isEqualTo(pkg2.domainSetId)
             assertThat(isLinkHandlingAllowed).isEqualTo(true)
             assertThat(user.identifier).isEqualTo(USER_ID)
@@ -164,7 +164,7 @@
         }
 
         assertThat(service.queryValidVerificationPackageNames())
-                .containsExactly(pkg1.getName(), pkg2.getName())
+                .containsExactly(pkg1.getPackageName(), pkg2.getPackageName())
     }
 
     @Test
@@ -175,7 +175,7 @@
             <domain-verifications>
                 <active>
                     <package-state
-                        packageName="${pkg1.getName()}"
+                        packageName="${pkg1.getPackageName()}"
                         id="${pkg1.domainSetId}"
                         signature="$DIGEST_ONE"
                         >
@@ -190,8 +190,8 @@
         val service = makeService(pkg1, pkg2)
         service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream()))
         service.addPackage(pkg1)
-        val info = service.getInfo(pkg1.getName())
-        assertThat(info.packageName).isEqualTo(pkg1.getName())
+        val info = service.getInfo(pkg1.getPackageName())
+        assertThat(info.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(info.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(info.hostToStateMap).containsExactlyEntriesIn(
             mapOf(
@@ -200,8 +200,8 @@
             )
         )
 
-        val userState = service.getUserState(pkg1.getName())
-        assertThat(userState.packageName).isEqualTo(pkg1.getName())
+        val userState = service.getUserState(pkg1.getPackageName())
+        assertThat(userState.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(userState.isLinkHandlingAllowed).isEqualTo(true)
         assertThat(userState.user.identifier).isEqualTo(USER_ID)
@@ -213,7 +213,7 @@
         )
 
         assertThat(service.queryValidVerificationPackageNames())
-            .containsExactly(pkg1.getName())
+            .containsExactly(pkg1.getPackageName())
     }
 
     @Test
@@ -224,7 +224,7 @@
             <domain-verifications>
                 <active>
                     <package-state
-                        packageName="${pkg1.getName()}"
+                        packageName="${pkg1.getPackageName()}"
                         id="${pkg1.domainSetId}"
                         signature="INVALID_SIGNATURE"
                         >
@@ -239,8 +239,8 @@
         val service = makeService(pkg1, pkg2)
         service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream()))
         service.addPackage(pkg1)
-        val info = service.getInfo(pkg1.getName())
-        assertThat(info.packageName).isEqualTo(pkg1.getName())
+        val info = service.getInfo(pkg1.getPackageName())
+        assertThat(info.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(info.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(info.hostToStateMap).containsExactlyEntriesIn(
             mapOf(
@@ -249,8 +249,8 @@
             )
         )
 
-        val userState = service.getUserState(pkg1.getName())
-        assertThat(userState.packageName).isEqualTo(pkg1.getName())
+        val userState = service.getUserState(pkg1.getPackageName())
+        assertThat(userState.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(userState.isLinkHandlingAllowed).isEqualTo(true)
         assertThat(userState.user.identifier).isEqualTo(USER_ID)
@@ -262,7 +262,7 @@
         )
 
         assertThat(service.queryValidVerificationPackageNames())
-            .containsExactly(pkg1.getName())
+            .containsExactly(pkg1.getPackageName())
     }
 
     @Test
@@ -273,7 +273,7 @@
             <domain-verifications>
                 <active>
                     <package-state
-                        packageName="${pkg1.getName()}"
+                        packageName="${pkg1.getPackageName()}"
                         id="${pkg1.domainSetId}"
                         >
                         <state>
@@ -311,8 +311,8 @@
 
         service.addPackage(pkg1)
 
-        val userState = service.getUserState(pkg1.getName())
-        assertThat(userState.packageName).isEqualTo(pkg1.getName())
+        val userState = service.getUserState(pkg1.getPackageName())
+        assertThat(userState.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(userState.isLinkHandlingAllowed).isEqualTo(false)
         assertThat(userState.user.identifier).isEqualTo(USER_ID)
@@ -348,7 +348,7 @@
             <domain-verifications>
                 <active>
                     <package-state
-                        packageName="${pkg1.getName()}"
+                        packageName="${pkg1.getPackageName()}"
                         id="${pkg1.domainSetId}"
                         signature="$DIGEST_ONE"
                         >
@@ -381,8 +381,8 @@
             service: DomainVerificationService,
             expectRestore: Boolean = false
     ) {
-        val info = service.getInfo(pkg1.getName())
-        assertThat(info.packageName).isEqualTo(pkg1.getName())
+        val info = service.getInfo(pkg1.getPackageName())
+        assertThat(info.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(info.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(info.hostToStateMap).containsExactlyEntriesIn(mapOf(
                 // To share the majority of code, special case restoration to check a different int
@@ -390,8 +390,8 @@
                 DOMAIN_2 to STATE_NO_RESPONSE,
         ))
 
-        val userState = service.getUserState(pkg1.getName())
-        assertThat(userState.packageName).isEqualTo(pkg1.getName())
+        val userState = service.getUserState(pkg1.getPackageName())
+        assertThat(userState.packageName).isEqualTo(pkg1.getPackageName())
         assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
         assertThat(userState.isLinkHandlingAllowed).isEqualTo(false)
         assertThat(userState.user.identifier).isEqualTo(USER_ID)
@@ -401,10 +401,10 @@
         ))
 
         assertThat(service.queryValidVerificationPackageNames())
-                .containsExactly(pkg1.getName())
+                .containsExactly(pkg1.getPackageName())
 
         // Re-enable link handling to check that the 3/4 domains were stripped
-        service.setDomainVerificationLinkHandlingAllowed(pkg1.getName(), true, USER_ID)
+        service.setDomainVerificationLinkHandlingAllowed(pkg1.getPackageName(), true, USER_ID)
 
         assertThat(service.getOwnersForDomain(DOMAIN_1, USER_ID))
                 .containsExactly(DomainOwner(PKG_ONE, false))
@@ -630,7 +630,7 @@
         serviceBefore.addPackage(pkg2)
 
         serviceBefore.setStatus(pkg1.domainSetId, setOf(DOMAIN_1), STATE_SUCCESS)
-        serviceBefore.setDomainVerificationLinkHandlingAllowed(pkg1.getName(), false, 10)
+        serviceBefore.setDomainVerificationLinkHandlingAllowed(pkg1.getPackageName(), false, 10)
         serviceBefore.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_2), true, 0)
         serviceBefore.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_3), true, 10)
 
@@ -758,11 +758,11 @@
         systemConfiguredPackageNames: ArraySet<String> = ArraySet(),
         vararg pkgSettings: PackageSetting
     ) = makeService(systemConfiguredPackageNames = systemConfiguredPackageNames) {
-        pkgName -> pkgSettings.find { pkgName == it.getName() }
+        pkgName -> pkgSettings.find { pkgName == it.getPackageName() }
     }
 
     private fun makeService(vararg pkgSettings: PackageSetting) =
-        makeService { pkgName -> pkgSettings.find { pkgName == it.getName() } }
+        makeService { pkgName -> pkgSettings.find { pkgName == it.getPackageName() } }
 
     private fun makeService(
         systemConfiguredPackageNames: ArraySet<String> = ArraySet(),
@@ -829,7 +829,7 @@
         }
 
         whenever(getPkg()) { pkg }
-        whenever(getName()) { pkgName }
+        whenever(getPackageName()) { pkgName }
         whenever(this.domainSetId) { domainSetId }
         whenever(getInstantApp(anyInt())) { false }
         whenever(firstInstallTime) { 0L }
@@ -845,8 +845,8 @@
         linkHandingAllowed: Boolean = true,
         hostToStateMap: Map<String, Int>
     ) {
-        getUserState(pkg.getName(), userId).apply {
-            assertThat(this.packageName).isEqualTo(pkg.getName())
+        getUserState(pkg.getPackageName(), userId).apply {
+            assertThat(this.packageName).isEqualTo(pkg.getPackageName())
             assertThat(this.identifier).isEqualTo(pkg.domainSetId)
             assertThat(this.isLinkHandlingAllowed).isEqualTo(linkHandingAllowed)
             assertThat(this.user.identifier).isEqualTo(userId)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 6a75795..32866ea 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -26,7 +26,6 @@
 import android.os.Build
 import android.os.Process
 import android.util.ArraySet
-import android.util.SparseArray
 import com.android.server.pm.PackageSetting
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageSettings
@@ -232,7 +231,7 @@
                 TEST_UUID
             )
         ) {
-            whenever(getName()) { TEST_PKG }
+            whenever(getPackageName()) { TEST_PKG }
             whenever(getPkg()) { mockPkg() }
             whenever(domainSetId) { TEST_UUID }
             whenever(readUserState(0)) { PackageUserState() }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 3e2853c..1d5e280 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -139,7 +139,7 @@
         }
 
         whenever(getPkg()) { pkg }
-        whenever(getName()) { pkgName }
+        whenever(getPackageName()) { pkgName }
         whenever(this.domainSetId) { domainSetId }
         whenever(getInstantApp(anyInt())) { false }
         whenever(firstInstallTime) { 0L }
diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file6.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file6.xml
new file mode 100644
index 0000000..b3c14228
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file6.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<sensor-privacy enabled="false">
+</sensor-privacy>
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 607fb47..40b3664 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -1003,6 +1003,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
+        verify(l, times(1)).updateBackgroundRestrictedForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
+                eq(true));
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1017,6 +1019,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
+        verify(l, times(1)).updateBackgroundRestrictedForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
+                eq(false));
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1030,6 +1034,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1047,6 +1053,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
+        verify(l, times(1)).updateBackgroundRestrictedForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
+                eq(true));
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1063,6 +1071,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1081,6 +1091,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1095,6 +1107,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1111,6 +1125,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1126,6 +1142,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1142,6 +1160,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1158,6 +1178,8 @@
         verify(l, times(2)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1172,6 +1194,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1188,6 +1212,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1203,6 +1229,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1225,6 +1253,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1240,6 +1270,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1255,6 +1287,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1270,6 +1304,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1286,6 +1322,8 @@
         verify(l, times(1)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(1)).updateAllAlarms();
         verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
@@ -1301,6 +1339,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1316,6 +1356,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1331,6 +1373,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1346,6 +1390,8 @@
         verify(l, times(0)).updateAllJobs();
         verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+        verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+                anyBoolean());
 
         verify(l, times(0)).updateAllAlarms();
         verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index acf50b45..e472b06 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -323,6 +323,7 @@
         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
         doNothing().when(mWakeLock).acquire();
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
+        doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), anyString(), any(), any());
         doNothing().when(mAlarmManager)
                 .setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any());
         doReturn(mock(Sensor.class)).when(mSensorManager)
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/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
index 15dfd26..609768c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 
+import android.app.ActivityManager;
 import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -56,6 +57,9 @@
 import java.time.ZoneOffset;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -66,6 +70,7 @@
  * Build/Install/Run:
  * atest FrameworksMockingServicesTests:CacheOomRankerTest
  */
+@SuppressWarnings("GuardedBy") // No tests are concurrent, so no need to test locking.
 @RunWith(MockitoJUnitRunner.class)
 public class CacheOomRankerTest {
     private static final Instant NOW = LocalDate.of(2021, 1, 1).atStartOfDay(
@@ -90,6 +95,7 @@
     private int mNextUid = 30000;
     private int mNextPackageUid = 40000;
     private int mNextPackageName = 1;
+    private Map<Integer, Long> mPidToRss;
 
     private TestExecutor mExecutor = new TestExecutor();
     private CacheOomRanker mCacheOomRanker;
@@ -115,7 +121,15 @@
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
 
-        mCacheOomRanker = new CacheOomRanker(mAms);
+        mPidToRss = new HashMap<>();
+        mCacheOomRanker = new CacheOomRanker(
+                mAms,
+                pid -> {
+                    Long rss = mPidToRss.get(pid);
+                    assertThat(rss).isNotNull();
+                    return new long[]{rss};
+                }
+        );
         mCacheOomRanker.init(mExecutor);
     }
 
@@ -183,6 +197,8 @@
     public void reRankLruCachedApps_lruImpactsOrdering() throws InterruptedException {
         setConfig(/* numberToReRank= */ 5,
                 /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 0.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */1.0f);
@@ -222,6 +238,8 @@
     public void reRankLruCachedApps_rssImpactsOrdering() throws InterruptedException {
         setConfig(/* numberToReRank= */ 6,
                 /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 0.0f,
                 /* pssWeight= */ 1.0f,
                 /* lruWeight= */ 0.0f);
@@ -260,9 +278,128 @@
     }
 
     @Test
+    public void reRankLruCachedApps_rssImpactsOrdering_cachedRssValues()
+            throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 10000000,
+                /* usesWeight= */ 0.0f,
+                /* pssWeight= */ 1.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
+        ProcessRecord rss10k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        processList.add(rss10k);
+        ProcessRecord rss20k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        processList.add(rss20k);
+        ProcessRecord rss1k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(60, ChronoUnit.MINUTES).toEpochMilli(), 1024L, 10000);
+        processList.add(rss1k);
+        ProcessRecord rss100k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        processList.add(rss100k);
+        ProcessRecord rss2k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        processList.add(rss2k);
+        ProcessRecord rss15k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 20);
+        processList.add(rss15k);
+        // Only re-ranking 6 entries so this should stay in most recent position.
+        ProcessRecord rss16k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 20);
+        processList.add(rss16k);
+        list.setLruProcessServiceStartLSP(processList.size());
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+        // First 6 ordered by largest pss, then last processes position unchanged.
+        assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k,
+                rss16k).inOrder();
+
+        // Clear mPidToRss so that Process.getRss calls fail.
+        mPidToRss.clear();
+        // Mix up the process list to ensure that CacheOomRanker actually re-ranks.
+        Collections.swap(processList, 0, 1);
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+        // Re ranking is the same.
+        assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k,
+                rss16k).inOrder();
+    }
+
+    @Test
+    public void reRankLruCachedApps_rssImpactsOrdering_profileRss()
+            throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ false,
+                /* rssUpdateRateMs= */ 10000000,
+                /* usesWeight= */ 0.0f,
+                /* pssWeight= */ 1.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
+        ProcessRecord rss10k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 0L, 1000);
+        rss10k.mProfile.setLastRss(10 * 1024L);
+        processList.add(rss10k);
+        ProcessRecord rss20k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 0L, 2000);
+        rss20k.mProfile.setLastRss(20 * 1024L);
+        processList.add(rss20k);
+        ProcessRecord rss1k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(60, ChronoUnit.MINUTES).toEpochMilli(), 0L, 10000);
+        rss1k.mProfile.setLastRss(1024L);
+        processList.add(rss1k);
+        ProcessRecord rss100k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 0L, 10);
+        rss100k.mProfile.setLastRss(100 * 1024L);
+        processList.add(rss100k);
+        ProcessRecord rss2k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 0L, 20);
+        rss2k.mProfile.setLastRss(2 * 1024L);
+        processList.add(rss2k);
+        ProcessRecord rss15k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 20);
+        rss15k.mProfile.setLastRss(15 * 1024L);
+        processList.add(rss15k);
+        // Only re-ranking 6 entries so this should stay in most recent position.
+        ProcessRecord rss16k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 20);
+        rss16k.mProfile.setLastRss(16 * 1024L);
+        processList.add(rss16k);
+        list.setLruProcessServiceStartLSP(processList.size());
+
+        // This should not be used, as RSS values are taken from mProfile.
+        mPidToRss.clear();
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+        // First 6 ordered by largest pss, then last processes position unchanged.
+        assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k,
+                rss16k).inOrder();
+
+        // Clear mPidToRss so that Process.getRss calls fail.
+        mPidToRss.clear();
+        // Mix up the process list to ensure that CacheOomRanker actually re-ranks.
+        Collections.swap(processList, 0, 1);
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+        // Re ranking is the same.
+        assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k,
+                rss16k).inOrder();
+    }
+
+
+    @Test
     public void reRankLruCachedApps_usesImpactsOrdering() throws InterruptedException {
         setConfig(/* numberToReRank= */ 4,
                 /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -301,6 +438,8 @@
     public void reRankLruCachedApps_fewProcesses() throws InterruptedException {
         setConfig(/* numberToReRank= */ 4,
                 /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -338,6 +477,8 @@
     public void reRankLruCachedApps_fewNonServiceProcesses() throws InterruptedException {
         setConfig(/* numberToReRank= */ 4,
                 /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -375,6 +516,8 @@
     public void reRankLruCachedApps_manyProcessesThenFew() throws InterruptedException {
         setConfig(/* numberToReRank= */ 6,
                 /* preserveTopNApps= */ 0,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -438,6 +581,8 @@
     public void reRankLruCachedApps_preservesTopNApps() throws InterruptedException {
         setConfig(/* numberToReRank= */ 6,
                 /* preserveTopNApps= */ 3,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -477,6 +622,8 @@
             throws InterruptedException {
         setConfig(/* numberToReRank= */ 6,
                 /* preserveTopNApps= */ 100,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -515,6 +662,8 @@
             throws InterruptedException {
         setConfig(/* numberToReRank= */ 6,
                 /* preserveTopNApps= */ -100,
+                /* useFrequentRss= */ true,
+                /* rssUpdateRateMs= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
@@ -549,8 +698,8 @@
                 used200).inOrder();
     }
 
-    private void setConfig(int numberToReRank, int preserveTopNApps, float usesWeight,
-            float pssWeight, float lruWeight)
+    private void setConfig(int numberToReRank, int preserveTopNApps, boolean useFrequentRss,
+            long rssUpdateRateMs, float usesWeight, float pssWeight, float lruWeight)
             throws InterruptedException {
         mExecutor.init(4);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -562,6 +711,14 @@
                 Integer.toString(preserveTopNApps),
                 false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_USE_FREQUENT_RSS,
+                Boolean.toString(useFrequentRss),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_RSS_UPDATE_RATE_MS,
+                Long.toString(rssUpdateRateMs),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
                 Float.toString(lruWeight),
                 false);
@@ -575,13 +732,15 @@
                 false);
         mExecutor.waitForLatch();
         assertThat(mCacheOomRanker.getNumberToReRank()).isEqualTo(numberToReRank);
+        assertThat(mCacheOomRanker.mUseFrequentRss).isEqualTo(useFrequentRss);
+        assertThat(mCacheOomRanker.mRssUpdateRateMs).isEqualTo(rssUpdateRateMs);
         assertThat(mCacheOomRanker.mRssWeight).isEqualTo(pssWeight);
         assertThat(mCacheOomRanker.mUsesWeight).isEqualTo(usesWeight);
         assertThat(mCacheOomRanker.mLruWeight).isEqualTo(lruWeight);
     }
 
     private ProcessRecord nextProcessRecord(int setAdj, long lastActivityTime, long lastRss,
-            int returnedToCacheCount) {
+            int wentToForegroundCount) {
         ApplicationInfo ai = new ApplicationInfo();
         ai.packageName = "a.package.name" + mNextPackageName++;
         ProcessRecord app = new ProcessRecord(mAms, ai, ai.packageName + ":process", mNextUid++);
@@ -591,11 +750,11 @@
         app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
         app.mState.setCurAdj(setAdj);
         app.setLastActivityTime(lastActivityTime);
-        app.mProfile.setLastRss(lastRss);
+        mPidToRss.put(app.getPid(), lastRss);
         app.mState.setCached(false);
-        for (int i = 0; i < returnedToCacheCount; ++i) {
-            app.mState.setCached(false);
-            app.mState.setCached(true);
+        for (int i = 0; i < wentToForegroundCount; ++i) {
+            app.mState.setSetProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+            app.mState.setSetProcState(ActivityManager.PROCESS_STATE_CACHED_RECENT);
         }
         // Sets the thread returned by ProcessRecord#getThread, which we use to check whether the
         // app is currently launching.
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/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 18f1267..284a754 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -2174,7 +2174,7 @@
         ConnectionRecord cr = spy(new ConnectionRecord(binding,
                 mock(ActivityServiceConnectionsHolder.class),
                 mock(IServiceConnection.class), bindFlags,
-                0, null, client.uid, client.processName, client.info.packageName));
+                0, null, client.uid, client.processName, client.info.packageName, null));
         doCallRealMethod().when(record).addConnection(any(IBinder.class),
                 any(ConnectionRecord.class));
         record.addConnection(binder, cr);
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 34856e2..28cdd63 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -142,6 +142,12 @@
                 .thenReturn(mockArray);
         when(mMockedResources.obtainTypedArray(R.array.config_waterfallCutoutArray))
                 .thenReturn(mockArray);
+        when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerRadiusArray))
+                .thenReturn(mockArray);
+        when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerTopRadiusArray))
+                .thenReturn(mockArray);
+        when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerBottomRadiusArray))
+                .thenReturn(mockArray);
     }
 
     @After
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 0fcda81..6a25560 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -678,6 +678,7 @@
 
     private void markImplicitConstraintsSatisfied(JobStatus job, boolean isSatisfied) {
         job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
+        job.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
         job.setDeviceNotDozingConstraintSatisfied(
                 sElapsedRealtimeClock.millis(), isSatisfied, false);
         job.setBackgroundNotRestrictedConstraintSatisfied(
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index dd70c87..4738159 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -389,6 +389,8 @@
                 /* state */ true, /* allowlisted */false);
         js.setBackgroundNotRestrictedConstraintSatisfied(
                 sElapsedRealtimeClock.millis(), true, false);
+        js.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+        js.setExpeditedJobTareApproved(sElapsedRealtimeClock.millis(), true);
         return js;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 3c97c95..9d89f12 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -103,7 +103,7 @@
     val dataAppDirectory: File =
             File(Files.createTempDirectory("data").toFile(), "app")
     val frameworkSignature: SigningDetails = SigningDetails(arrayOf(generateSpySignature()), 3)
-    val systemPartitions: List<PackageManagerService.ScanPartition> =
+    val systemPartitions: List<ScanPartition> =
             redirectScanPartitions(PackageManagerService.SYSTEM_PARTITIONS)
     val session: StaticMockitoSession
 
@@ -476,7 +476,7 @@
     }
 
     /** Finds the appropriate partition, if available, based on a scan flag unique to it.  */
-    fun getPartitionFromFlag(scanFlagMask: Int): PackageManagerService.ScanPartition =
+    fun getPartitionFromFlag(scanFlagMask: Int): ScanPartition =
             systemPartitions.first { (it.scanFlag and scanFlagMask) != 0 }
 
     @Throws(Exception::class)
@@ -630,11 +630,11 @@
     /** Override get*Folder methods to point to temporary local directories  */
 
     @Throws(IOException::class)
-    private fun redirectScanPartitions(partitions: List<PackageManagerService.ScanPartition>):
-            List<PackageManagerService.ScanPartition> {
-        val spiedPartitions: MutableList<PackageManagerService.ScanPartition> =
+    private fun redirectScanPartitions(partitions: List<ScanPartition>):
+            List<ScanPartition> {
+        val spiedPartitions: MutableList<ScanPartition> =
                 ArrayList(partitions.size)
-        for (partition: PackageManagerService.ScanPartition in partitions) {
+        for (partition: ScanPartition in partitions) {
             val spy = spy(partition)
             val newRoot = Files.createTempDirectory(partition.folder.name).toFile()
             whenever(spy.overlayFolder).thenReturn(File(newRoot, "overlay"))
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index ba5a58f..b60e0c3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -30,17 +31,23 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
+import android.apex.ApexInfo;
 import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
 import android.content.Context;
 import android.content.IntentSender;
+import android.content.pm.ApexStagedEvent;
+import android.content.pm.IStagedApexObserver;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
+import android.content.pm.StagedApexInfo;
+import android.os.Message;
 import android.os.SystemProperties;
 import android.os.storage.IStorageManager;
 import android.platform.test.annotations.Presubmit;
+import android.util.IntArray;
 import android.util.SparseArray;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -55,15 +62,20 @@
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
+import org.mockito.invocation.InvocationOnMock;
 import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Predicate;
 
 @Presubmit
@@ -527,6 +539,281 @@
         assertThat(mStagingManager.getSessionIdByPackageName("com.bar")).isEqualTo(-1);
     }
 
+    @Test
+    public void getStagedApexInfos_validatePreConditions() throws Exception {
+        // Invalid session: null session
+        {
+            // Call and verify
+            IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                    () -> mStagingManager.getStagedApexInfos(null));
+            assertThat(thrown).hasMessageThat().contains("Session is null");
+        }
+        // Invalid session: has parent
+        {
+            FakeStagedSession session = new FakeStagedSession(241);
+            session.setParentSessionId(239);
+            session.setSessionReady();
+            // Call and verify
+            IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                    () -> mStagingManager.getStagedApexInfos(session));
+            assertThat(thrown).hasMessageThat().contains("241 session has parent");
+        }
+
+        // Invalid session: does not contain apex
+        {
+            FakeStagedSession session = new FakeStagedSession(241);
+            session.setSessionReady();
+            // Call and verify
+            IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                    () -> mStagingManager.getStagedApexInfos(session));
+            assertThat(thrown).hasMessageThat().contains("241 session does not contain apex");
+        }
+        // Invalid session: not ready
+        {
+            FakeStagedSession session = new FakeStagedSession(239);
+            session.setIsApex(true);
+            // Call and verify
+            Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(session);
+            assertThat(result).isEmpty();
+        }
+        // Invalid session: destroyed
+        {
+            FakeStagedSession session = new FakeStagedSession(240);
+            session.setSessionReady();
+            session.setIsApex(true);
+            session.setDestroyed(true);
+            // Call and verify
+            Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(session);
+            assertThat(result).isEmpty();
+        }
+    }
+
+    private ApexInfo[] getFakeApexInfo(List<String> moduleNames) {
+        List<ApexInfo> result = new ArrayList<>();
+        for (String moduleName : moduleNames) {
+            ApexInfo info = new ApexInfo();
+            info.moduleName = moduleName;
+            result.add(info);
+        }
+        return result.toArray(new ApexInfo[0]);
+    }
+
+    @Test
+    public void getStagedApexInfos_nonParentSession() throws Exception {
+        FakeStagedSession validSession = new FakeStagedSession(239);
+        validSession.setIsApex(true);
+        validSession.setSessionReady();
+        ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1"));
+        when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
+
+        // Call and verify
+        Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(validSession);
+        assertThat(result).containsExactly(fakeApexInfos[0].moduleName, fakeApexInfos[0]);
+
+        ArgumentCaptor<ApexSessionParams> argumentCaptor =
+                ArgumentCaptor.forClass(ApexSessionParams.class);
+        verify(mApexManager, times(1)).getStagedApexInfos(argumentCaptor.capture());
+        ApexSessionParams params = argumentCaptor.getValue();
+        assertThat(params.sessionId).isEqualTo(239);
+    }
+
+    @Test
+    public void getStagedApexInfos_parentSession() throws Exception {
+        FakeStagedSession childSession1 = new FakeStagedSession(201);
+        childSession1.setIsApex(true);
+        FakeStagedSession childSession2 = new FakeStagedSession(202);
+        childSession2.setIsApex(true);
+        FakeStagedSession nonApexChild = new FakeStagedSession(203);
+        FakeStagedSession parentSession = new FakeStagedSession(239,
+                Arrays.asList(childSession1, childSession2, nonApexChild));
+        parentSession.setSessionReady();
+        ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1", "module2"));
+        when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
+
+        // Call and verify
+        Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(parentSession);
+        assertThat(result).containsExactly(fakeApexInfos[0].moduleName, fakeApexInfos[0],
+                fakeApexInfos[1].moduleName, fakeApexInfos[1]);
+
+        ArgumentCaptor<ApexSessionParams> argumentCaptor =
+                ArgumentCaptor.forClass(ApexSessionParams.class);
+        verify(mApexManager, times(1)).getStagedApexInfos(argumentCaptor.capture());
+        ApexSessionParams params = argumentCaptor.getValue();
+        assertThat(params.sessionId).isEqualTo(239);
+        assertThat(params.childSessionIds).asList().containsExactly(201, 202);
+    }
+
+    @Test
+    public void getStagedApexModuleNames_returnsStagedApexModules() throws Exception {
+        FakeStagedSession validSession1 = new FakeStagedSession(239);
+        validSession1.setIsApex(true);
+        validSession1.setSessionReady();
+        mStagingManager.createSession(validSession1);
+
+        FakeStagedSession childSession1 = new FakeStagedSession(123);
+        childSession1.setIsApex(true);
+        FakeStagedSession childSession2 = new FakeStagedSession(124);
+        childSession2.setIsApex(true);
+        FakeStagedSession nonApexChild = new FakeStagedSession(125);
+        FakeStagedSession parentSession = new FakeStagedSession(240,
+                Arrays.asList(childSession1, childSession2, nonApexChild));
+        parentSession.setSessionReady();
+        mStagingManager.createSession(parentSession);
+
+        mockApexManagerGetStagedApexInfoWithSessionId();
+
+        List<String> result = mStagingManager.getStagedApexModuleNames();
+        assertThat(result).containsExactly("239", "123", "124");
+        verify(mApexManager, times(2)).getStagedApexInfos(any());
+    }
+
+    // Make mApexManager return ApexInfo with same module name as the sessionId
+    // of the parameter that was passed into it
+    private void mockApexManagerGetStagedApexInfoWithSessionId() {
+        when(mApexManager.getStagedApexInfos(any())).thenAnswer(new Answer<ApexInfo[]>() {
+            @Override
+            public ApexInfo[] answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                ApexSessionParams params = (ApexSessionParams) args[0];
+                IntArray sessionsToProcess = new IntArray();
+                if (params.childSessionIds.length == 0) {
+                    sessionsToProcess.add(params.sessionId);
+                } else {
+                    sessionsToProcess.addAll(params.childSessionIds);
+                }
+                List<ApexInfo> result = new ArrayList<>();
+                for (int session : sessionsToProcess.toArray()) {
+                    ApexInfo info = new ApexInfo();
+                    info.moduleName = String.valueOf(session);
+                    result.add(info);
+                }
+                return result.toArray(new ApexInfo[0]);
+            }
+        });
+    }
+
+    @Test
+    public void getStagedApexInfo() throws Exception {
+        FakeStagedSession validSession1 = new FakeStagedSession(239);
+        validSession1.setIsApex(true);
+        validSession1.setSessionReady();
+        mStagingManager.createSession(validSession1);
+        ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1"));
+        when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
+
+        // Verify null is returned if module name is not found
+        StagedApexInfo result = mStagingManager.getStagedApexInfo("not found");
+        assertThat(result).isNull();
+        verify(mApexManager, times(1)).getStagedApexInfos(any());
+        // Otherwise, the correct object is returned
+        result = mStagingManager.getStagedApexInfo("module1");
+        assertThat(result.moduleName).isEqualTo(fakeApexInfos[0].moduleName);
+        assertThat(result.diskImagePath).isEqualTo(fakeApexInfos[0].modulePath);
+        assertThat(result.versionCode).isEqualTo(fakeApexInfos[0].versionCode);
+        assertThat(result.versionName).isEqualTo(fakeApexInfos[0].versionName);
+        verify(mApexManager, times(2)).getStagedApexInfos(any());
+    }
+
+    @Test
+    public void registeredStagedApexObserverIsNotifiedOnPreRebootVerificationCompletion()
+            throws Exception {
+        // Register observer
+        IStagedApexObserver observer = Mockito.mock(IStagedApexObserver.class);
+        mStagingManager.registerStagedApexObserver(observer);
+
+        // Create one staged session and trigger end of pre-reboot verification
+        {
+            FakeStagedSession session = new FakeStagedSession(239);
+            session.setIsApex(true);
+            mStagingManager.createSession(session);
+
+            mockApexManagerGetStagedApexInfoWithSessionId();
+            triggerEndOfPreRebootVerification(session);
+
+            assertThat(session.isSessionReady()).isTrue();
+            ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
+                    ApexStagedEvent.class);
+            verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
+            assertThat(argumentCaptor.getValue().stagedApexModuleNames).isEqualTo(
+                    new String[]{"239"});
+        }
+
+        // Create another staged session and verify observers are notified of union
+        {
+            Mockito.clearInvocations(observer);
+            FakeStagedSession session = new FakeStagedSession(240);
+            session.setIsApex(true);
+            mStagingManager.createSession(session);
+
+            triggerEndOfPreRebootVerification(session);
+
+            assertThat(session.isSessionReady()).isTrue();
+            ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
+                    ApexStagedEvent.class);
+            verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
+            assertThat(argumentCaptor.getValue().stagedApexModuleNames).isEqualTo(
+                    new String[]{"239", "240"});
+        }
+
+        // Finally, verify that once unregistered, observer is not notified
+        mStagingManager.unregisterStagedApexObserver(observer);
+        {
+            Mockito.clearInvocations(observer);
+            FakeStagedSession session = new FakeStagedSession(241);
+            session.setIsApex(true);
+            mStagingManager.createSession(session);
+
+            triggerEndOfPreRebootVerification(session);
+
+            assertThat(session.isSessionReady()).isTrue();
+            verify(observer, never()).onApexStaged(any());
+        }
+    }
+
+    @Test
+    public void registeredStagedApexObserverIsNotifiedOnSessionAbandon() throws Exception {
+        // Register observer
+        IStagedApexObserver observer = Mockito.mock(IStagedApexObserver.class);
+        mStagingManager.registerStagedApexObserver(observer);
+
+        // Create a ready session and abandon it
+        FakeStagedSession session = new FakeStagedSession(239);
+        session.setIsApex(true);
+        session.setSessionReady();
+        session.setDestroyed(true);
+        mStagingManager.createSession(session);
+
+        mStagingManager.abortCommittedSession(session);
+
+        assertThat(session.isSessionReady()).isTrue();
+        ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
+                ApexStagedEvent.class);
+        verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue().stagedApexModuleNames).hasLength(0);
+    }
+
+    @Test
+    public void stagedApexObserverIsOnlyCalledForApexSessions() throws Exception {
+        IStagedApexObserver observer = Mockito.mock(IStagedApexObserver.class);
+        mStagingManager.registerStagedApexObserver(observer);
+
+        //  Trigger end of pre-reboot verification
+        FakeStagedSession session = new FakeStagedSession(239);
+        mStagingManager.createSession(session);
+
+        triggerEndOfPreRebootVerification(session);
+        assertThat(session.isSessionReady()).isTrue();
+        verify(observer, never()).onApexStaged(any());
+    }
+
+    private void triggerEndOfPreRebootVerification(StagingManager.StagedSession session) {
+        StagingManager.PreRebootVerificationHandler handler =
+                mStagingManager.mPreRebootVerificationHandler;
+        Message msg =  handler.obtainMessage(
+                handler.MSG_PRE_REBOOT_VERIFICATION_END, session.sessionId(), -1, session);
+        handler.handleMessage(msg);
+    }
+
     private StagingManager.StagedSession createSession(int sessionId, String packageName,
             long committedMillis) {
         PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
@@ -591,10 +878,16 @@
         private String mPackageName;
         private boolean mIsAbandonded = false;
         private boolean mVerificationStarted = false;
-        private final List<StagingManager.StagedSession> mChildSessions = new ArrayList<>();
+        private final List<StagingManager.StagedSession> mChildSessions;
 
         private FakeStagedSession(int sessionId) {
             mSessionId = sessionId;
+            mChildSessions = new ArrayList<>();
+        }
+
+        private FakeStagedSession(int sessionId, List<StagingManager.StagedSession> childSessions) {
+            mSessionId = sessionId;
+            mChildSessions = childSessions;
         }
 
         private void setParentSessionId(int parentSessionId) {
@@ -777,9 +1070,7 @@
         }
 
         @Override
-        public void notifyEndPreRebootVerification() {
-            throw new UnsupportedOperationException();
-        }
+        public void notifyEndPreRebootVerification() {}
 
         @Override
         public void verifySession() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt
index 7a6110b..f17fa62 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt
@@ -79,8 +79,8 @@
         mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
         mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
 
-        pms.sendPackagesSuspendedForUser(
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
+        pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
+                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
         verify(pms).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
                 anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
 
@@ -97,8 +97,8 @@
         mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
         mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
 
-        pms.sendPackagesSuspendedForUser(
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
+        pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
+                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
         verify(pms, times(2)).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
                 anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
 
@@ -118,8 +118,8 @@
         mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
         mockAllowList(packageSetting2, null)
 
-        pms.sendPackagesSuspendedForUser(
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
+        pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
+                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
         verify(pms, times(2)).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
                 anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
 
@@ -133,6 +133,22 @@
         }
     }
 
+    @Test
+    @Throws(Exception::class)
+    fun sendPackagesSuspendModifiedForUser() {
+        pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+        verify(pms).sendPackageBroadcast(
+                eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
+                anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
+
+        var modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+        var modifiedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
+        assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
+        assertThat(modifiedUids).asList().containsExactly(
+                packageSetting1.appId, packageSetting2.appId)
+    }
+
     private fun allowList(vararg uids: Int) = SparseArray<IntArray>().apply {
         this.put(TEST_USER_ID, uids)
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java
index 844687f..ba79a76 100644
--- a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java
@@ -60,6 +60,8 @@
             String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 4);
     public static final String PERSISTENCE_FILE5 =
             String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 5);
+    public static final String PERSISTENCE_FILE6 =
+            String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 6);
 
     private Context mContext;
     @Mock
@@ -111,6 +113,7 @@
             initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE3);
             initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE4);
             initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE5);
+            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE6);
 
             // Try all files with two known users
             doReturn(new int[]{0, 10}).when(mMockedUserManagerInternal).getUserIds();
@@ -124,6 +127,7 @@
             initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE3);
             initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE4);
             initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE5);
+            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE6);
 
         } finally {
             mockitoSession.finishMocking();
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
new file mode 100644
index 0000000..dd6b744
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.tare;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.content.Context;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/** Tests various aspects of the Agent. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AgentTest {
+    private MockitoSession mMockingSession;
+    @Mock
+    private CompleteEconomicPolicy mEconomicPolicy;
+    @Mock
+    private Context mContext;
+    @Mock
+    private InternalResourceService mIrs;
+
+    @Before
+    public void setUp() {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .mockStatic(LocalServices.class)
+                .startMocking();
+        when(mIrs.getContext()).thenReturn(mContext);
+        when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mock(AlarmManager.class));
+    }
+
+    @After
+    public void tearDown() {
+        if (mMockingSession != null) {
+            mMockingSession.finishMocking();
+        }
+    }
+
+    @Test
+    public void testRecordTransaction_UnderMax() {
+        Agent agent = new Agent(mIrs, mEconomicPolicy);
+        Ledger ledger = new Ledger();
+
+        doReturn(1_000_000L).when(mIrs).getMaxCirculationLocked();
+        doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance();
+
+        Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(5, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 995);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1000, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -500);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(500, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 999_500L);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1_000_000L, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -1_000_001L);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(-1, ledger.getCurrentBalance());
+    }
+
+    @Test
+    public void testRecordTransaction_MaxCirculation() {
+        Agent agent = new Agent(mIrs, mEconomicPolicy);
+        Ledger ledger = new Ledger();
+
+        doReturn(1000L).when(mIrs).getMaxCirculationLocked();
+        doReturn(1000L).when(mEconomicPolicy).getMaxSatiatedBalance();
+
+        Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(5, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 995);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1000, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -500);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(500, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 2000);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1000, ledger.getCurrentBalance());
+
+        // MaxCirculation can change as the battery level changes. Any already allocated ARCSs
+        // shouldn't be removed by recordTransaction().
+        doReturn(900L).when(mIrs).getMaxCirculationLocked();
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 100);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1000, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -50);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(950, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -200);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(750, ledger.getCurrentBalance());
+
+        doReturn(800L).when(mIrs).getMaxCirculationLocked();
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 100);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(800, ledger.getCurrentBalance());
+    }
+
+    @Test
+    public void testRecordTransaction_MaxSatiatedBalance() {
+        Agent agent = new Agent(mIrs, mEconomicPolicy);
+        Ledger ledger = new Ledger();
+
+        doReturn(1_000_000L).when(mIrs).getMaxCirculationLocked();
+        doReturn(1000L).when(mEconomicPolicy).getMaxSatiatedBalance();
+
+        Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(5, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 995);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1000, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -500);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(500, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 999_500L);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1_000, ledger.getCurrentBalance());
+
+        // Shouldn't change in normal operation, but adding test case in case it does.
+        doReturn(900L).when(mEconomicPolicy).getMaxSatiatedBalance();
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, 500);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(1_000, ledger.getCurrentBalance());
+
+        transaction = new Ledger.Transaction(0, 0, 0, null, -1001);
+        agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
+        assertEquals(-1, ledger.getCurrentBalance());
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS b/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS
new file mode 100644
index 0000000..217a5ed
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d1afa1a..ef9248a 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -37,7 +37,6 @@
         "services.net",
         "services.people",
         "services.usage",
-        "services.uwb",
         "guava",
         "guava-android-testlib",
         "androidx.test.core",
@@ -87,7 +86,6 @@
 
     // These are not normally accessible from apps so they must be explicitly included.
     jni_libs: [
-        "libbacktrace",
         "libbase",
         "libbinder",
         "libc++",
@@ -145,7 +143,6 @@
         "utils/**/*.java",
         "utils/**/*.kt",
         "utils-mockito/**/*.kt",
-        ":services.core-sources-deviceconfig-interface",
     ],
     static_libs: [
         "junit",
@@ -162,7 +159,6 @@
         "utils/**/*.java",
         "utils/**/*.kt",
         "utils-mockito/**/*.kt",
-        ":services.core-sources-deviceconfig-interface",
     ],
     static_libs: [
         "junit",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index bcb2cf8..68b8469 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -71,6 +71,7 @@
     <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"/>
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/>
+    <uses-permission android:name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"/>
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.HARDWARE_TEST"/>
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index b580eae..327a80e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -55,6 +55,7 @@
 import android.support.test.uiautomator.UiDevice;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.text.TextUtils;
+import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.Pair;
 
@@ -99,6 +100,8 @@
     private static final String ACTION_FGS_STATS_TEST =
             "com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
     private static final String EXTRA_MESSENGER = "extra_messenger";
+    private static final String ACTION_RECEIVER_TEST =
+            "com.android.servicestests.apps.simpleservicetestapp.TEST";
 
     private static final String EXTRA_CALLBACK = "callback";
     private static final String EXTRA_COMMAND = "command";
@@ -467,6 +470,8 @@
             sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP2, TEST_APP1, null);
             runShellCommand("cmd deviceidle whitelist -" + TEST_APP1);
             runShellCommand("cmd deviceidle whitelist -" + TEST_APP2);
+            am.forceStopPackage(TEST_APP1);
+            am.forceStopPackage(TEST_APP2);
         }
     }
 
@@ -501,6 +506,206 @@
         return false;
     }
 
+    @LargeTest
+    @Test
+    public void testKillAppIfBgRestrictedCachedIdle() throws Exception {
+        final long shortTimeoutMs = 5_000;
+        final long backgroundSettleMs = 10_000;
+        final PackageManager pm = mContext.getPackageManager();
+        final int uid = pm.getPackageUid(TEST_APP1, 0);
+        final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid);
+        final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid);
+        final MyUidImportanceListener uidListener3 = new MyUidImportanceListener(uid);
+        SettingsSession<String> amConstantsSettings = null;
+        DeviceConfigSession<Boolean> killBgRestrictedAndCachedIdle = null;
+        DeviceConfigSession<Long> killBgRestrictedAndCachedIdleSettleTime = null;
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        final CountDownLatch[] latchHolder = new CountDownLatch[1];
+        final H handler = new H(Looper.getMainLooper(), latchHolder);
+        final Messenger messenger = new Messenger(handler);
+        try {
+            am.addOnUidImportanceListener(uidListener1,
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+            am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE);
+            am.addOnUidImportanceListener(uidListener3, RunningAppProcessInfo.IMPORTANCE_CACHED);
+            toggleScreenOn(true);
+
+            killBgRestrictedAndCachedIdle = new DeviceConfigSession<>(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    ActivityManagerConstants.KEY_KILL_BG_RESTRICTED_CACHED_IDLE,
+                    DeviceConfig::getBoolean,
+                    ActivityManagerConstants.DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE);
+            killBgRestrictedAndCachedIdle.set(true);
+            killBgRestrictedAndCachedIdleSettleTime = new DeviceConfigSession<>(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    ActivityManagerConstants.KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
+                    DeviceConfig::getLong,
+                    ActivityManagerConstants.DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
+            killBgRestrictedAndCachedIdleSettleTime.set(backgroundSettleMs);
+            amConstantsSettings = new SettingsSession<>(
+                Settings.Global.getUriFor(Settings.Global.ACTIVITY_MANAGER_CONSTANTS),
+                Settings.Global::getString, Settings.Global::putString);
+            final KeyValueListParser parser = new KeyValueListParser(',');
+            long currentBackgroundSettleMs =
+                    ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME;
+            try {
+                parser.setString(amConstantsSettings.get());
+                currentBackgroundSettleMs = parser.getLong(
+                        ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME,
+                        ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME);
+            } catch (IllegalArgumentException e) {
+            }
+            // Drain queue to make sure the existing UID_IDLE_MSG has been processed.
+            Thread.sleep(currentBackgroundSettleMs);
+            amConstantsSettings.set(
+                    ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME + "=" + backgroundSettleMs);
+
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+
+            final Intent intent = new Intent(ACTION_FGS_STATS_TEST);
+            final ComponentName cn = ComponentName.unflattenFromString(
+                    TEST_APP1 + "/" + TEST_FGS_CLASS);
+            final Bundle bundle = new Bundle();
+            intent.setComponent(cn);
+            bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder());
+            intent.putExtras(bundle);
+
+            // Start the FGS.
+            latchHolder[0] = new CountDownLatch(1);
+            mContext.startForegroundService(intent);
+            assertTrue("Timed out to start fg service", uidListener1.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+            assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Stop the FGS, it shouldn't be killed because it's not in FAS state.
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+            assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Set the FAS state.
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+            // Now it should've been killed.
+            assertTrue("Should have been killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Start the FGS.
+            // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+            latchHolder[0] = new CountDownLatch(1);
+            mContext.startForegroundService(intent);
+            assertTrue("Timed out to start fg service", uidListener1.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+            assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+            // It shouldn't be killed since it's not cached.
+            assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Stop the FGS, it should get killed because it's cached & uid idle & in FAS state.
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+            assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            assertTrue("Should have been killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Start the FGS.
+            // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+            latchHolder[0] = new CountDownLatch(1);
+            mContext.startForegroundService(intent);
+            assertTrue("Timed out to start fg service", uidListener1.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+            assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+            // It shouldn't be killed since it's not cached.
+            assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Stop the FGS.
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+            assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            assertTrue("Should have been in cached state", uidListener3.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_CACHED, shortTimeoutMs));
+            final long now = SystemClock.uptimeMillis();
+            // Sleep a while to let the UID idle ticking.
+            Thread.sleep(shortTimeoutMs);
+            // Now send a broadcast, it should bring the app out of cached for a while.
+            final Intent intent2 = new Intent(ACTION_RECEIVER_TEST);
+            final Bundle extras = new Bundle();
+            final IRemoteCallback callback = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    latchHolder[0].countDown();
+                }
+            };
+            extras.putBinder(EXTRA_CALLBACK, callback.asBinder());
+            intent2.putExtras(extras);
+            intent2.setPackage(TEST_APP1);
+            latchHolder[0] = new CountDownLatch(1);
+            mContext.sendBroadcast(intent2);
+            assertTrue("Timed out to wait for receiving broadcast", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            // Try to wait for the killing, it should be killed after backgroundSettleMs
+            // since receiving the broadcast
+            assertFalse("Shouldn't be killed now", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE,
+                    backgroundSettleMs + now - SystemClock.uptimeMillis() + 2_000));
+            // Now wait a bit longer, it should be killed.
+            assertTrue("Should have been killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Disable this FAS cached idle kill feature.
+            killBgRestrictedAndCachedIdle.set(false);
+
+            // Start the FGS.
+            // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+            latchHolder[0] = new CountDownLatch(1);
+            mContext.startForegroundService(intent);
+            assertTrue("Timed out to start fg service", uidListener1.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+            assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+            assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+            // Stop the FGS, it shouldn't be killed because the feature has been turned off.
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+            assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+                    shortTimeoutMs, TimeUnit.MILLISECONDS));
+            assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+        } finally {
+            runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND default");
+            if (amConstantsSettings != null) {
+                amConstantsSettings.close();
+            }
+            if (killBgRestrictedAndCachedIdle != null) {
+                killBgRestrictedAndCachedIdle.close();
+            }
+            if (killBgRestrictedAndCachedIdleSettleTime != null) {
+                killBgRestrictedAndCachedIdleSettleTime.close();
+            }
+            am.removeOnUidImportanceListener(uidListener1);
+            am.removeOnUidImportanceListener(uidListener2);
+            am.removeOnUidImportanceListener(uidListener3);
+            am.forceStopPackage(TEST_APP1);
+        }
+    }
+
     @Ignore("Need to disable calling uid check in ActivityManagerService.killPids before this test")
     @Test
     public void testKillPids() throws Exception {
@@ -717,6 +922,7 @@
         static final int MSG_DONE = 1;
         static final int MSG_START_FOREGROUND = 2;
         static final int MSG_STOP_FOREGROUND = 3;
+        static final int MSG_STOP_SERVICE = 4;
 
         private Messenger mRemoteMessenger;
         private CountDownLatch[] mLatchHolder;
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/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index 0d475c0..91bf4d1 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -135,7 +135,8 @@
                         "schema1",
                         ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         // "schema1" is platform hidden now and package visible to package1
         assertThat(mVisibilityStore.isSchemaSearchableByCaller(
@@ -167,7 +168,8 @@
                         "schema1",
                         ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         // Check that "schema1" still has the same visibility settings
         SystemUtil.runWithShellPermissionIdentity(() -> assertThat(
@@ -241,7 +243,8 @@
                         "schema1",
                         ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         // "schema1" is platform hidden now and package accessible
         assertThat(mVisibilityStore.isSchemaSearchableByCaller(
@@ -269,7 +272,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ true,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         // Check that "schema1" is no longer considered platform hidden or package accessible
         assertThat(mVisibilityStore.isSchemaSearchableByCaller(
@@ -298,7 +302,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         assertThat(mVisibilityStore.isSchemaSearchableByCaller(
                 "package",
@@ -333,7 +338,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         assertThat(mVisibilityStore.isSchemaSearchableByCaller(
                 "package",
@@ -361,7 +367,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.singletonList("Schema"),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
 
         assertThat(mVisibilityStore.isSchemaSearchableByCaller(
                 "package",
@@ -390,7 +397,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
         assertThat(mVisibilityStore
                                 .isSchemaSearchableByCaller(
                                         "package",
@@ -431,7 +439,8 @@
                         "Schema",
                         ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
                 /*forceOverride=*/ false,
-                /*schemaVersion=*/ 0);
+                /*schemaVersion=*/ 0,
+                /*setSchemaStatsBuilder=*/ null);
         assertThat(mVisibilityStore
                                 .isSchemaSearchableByCaller(
                                         "package",
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index f40a5ad..dd3b3ec 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -76,13 +76,14 @@
 import java.util.Set;
 
 public class AppSearchImplTest {
-    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
-    private AppSearchImpl mAppSearchImpl;
     /**
      * Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
      */
     private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
 
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+    private AppSearchImpl mAppSearchImpl;
+
     @Before
     public void setUp() throws Exception {
         mAppSearchImpl =
@@ -439,7 +440,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert a document and then remove it to generate garbage.
         GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
@@ -499,7 +501,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert a valid doc
         GenericDocument validDoc =
@@ -591,7 +594,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert a valid doc
         appSearchImpl.putDocument(
@@ -626,7 +630,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert document
         GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
@@ -660,7 +665,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "package",
                 "database2",
@@ -669,7 +675,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert documents
         GenericDocument document1 =
@@ -714,7 +721,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert document
         GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
@@ -756,7 +764,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert package2 schema
         List<AppSearchSchema> schema2 =
@@ -769,7 +778,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert package1 document
         GenericDocument document =
@@ -812,7 +822,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert package2 schema
         List<AppSearchSchema> schema2 =
@@ -825,7 +836,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert package1 document
         GenericDocument document =
@@ -889,7 +901,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -914,7 +927,8 @@
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
 
         long nextPageToken = searchResultPage.getNextPageToken();
-        searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+        searchResultPage =
+                mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
         assertThat(searchResultPage.getResults()).hasSize(1);
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
     }
@@ -932,7 +946,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -962,14 +977,17 @@
         AppSearchException e =
                 assertThrows(
                         AppSearchException.class,
-                        () -> mAppSearchImpl.getNextPage("package2", nextPageToken));
+                        () ->
+                                mAppSearchImpl.getNextPage(
+                                        "package2", nextPageToken, /*statsBuilder=*/ null));
         assertThat(e)
                 .hasMessageThat()
                 .contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
         assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
 
         // Can continue getting next page for package1
-        searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+        searchResultPage =
+                mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
         assertThat(searchResultPage.getResults()).hasSize(1);
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
     }
@@ -987,7 +1005,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -1019,7 +1038,8 @@
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
 
         long nextPageToken = searchResultPage.getNextPageToken();
-        searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+        searchResultPage =
+                mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
         assertThat(searchResultPage.getResults()).hasSize(1);
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
     }
@@ -1037,7 +1057,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -1074,14 +1095,17 @@
         AppSearchException e =
                 assertThrows(
                         AppSearchException.class,
-                        () -> mAppSearchImpl.getNextPage("package2", nextPageToken));
+                        () ->
+                                mAppSearchImpl.getNextPage(
+                                        "package2", nextPageToken, /*statsBuilder=*/ null));
         assertThat(e)
                 .hasMessageThat()
                 .contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
         assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
 
         // Can continue getting next page for package1
-        searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+        searchResultPage =
+                mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
         assertThat(searchResultPage.getResults()).hasSize(1);
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
     }
@@ -1099,7 +1123,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -1132,7 +1157,9 @@
         AppSearchException e =
                 assertThrows(
                         AppSearchException.class,
-                        () -> mAppSearchImpl.getNextPage("package1", nextPageToken));
+                        () ->
+                                mAppSearchImpl.getNextPage(
+                                        "package1", nextPageToken, /*statsBuilder=*/ null));
         assertThat(e)
                 .hasMessageThat()
                 .contains("Package \"package1\" cannot use nextPageToken: " + nextPageToken);
@@ -1152,7 +1179,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -1189,7 +1217,8 @@
         assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
 
         // Can continue getting next page for package1
-        searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+        searchResultPage =
+                mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
         assertThat(searchResultPage.getResults()).hasSize(1);
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
     }
@@ -1207,7 +1236,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -1247,7 +1277,9 @@
         AppSearchException e =
                 assertThrows(
                         AppSearchException.class,
-                        () -> mAppSearchImpl.getNextPage("package1", nextPageToken));
+                        () ->
+                                mAppSearchImpl.getNextPage(
+                                        "package1", nextPageToken, /*statsBuilder=*/ null));
         assertThat(e)
                 .hasMessageThat()
                 .contains("Package \"package1\" cannot use nextPageToken: " + nextPageToken);
@@ -1267,7 +1299,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two package1 documents
         GenericDocument document1 =
@@ -1311,7 +1344,8 @@
         assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
 
         // Can continue getting next page for package1
-        searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+        searchResultPage =
+                mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
         assertThat(searchResultPage.getResults()).hasSize(1);
         assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
     }
@@ -1355,7 +1389,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Create expected schemaType proto.
         SchemaProto expectedProto =
@@ -1400,7 +1435,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Create incompatible schema
         List<AppSearchSchema> newSchemas =
@@ -1416,7 +1452,8 @@
                         /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                         /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                         /*forceOverride=*/ true,
-                        /*version=*/ 0);
+                        /*version=*/ 0,
+                        /* setSchemaStatsBuilder= */ null);
         assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Text");
         assertThat(setSchemaResponse.getIncompatibleTypes()).containsExactly("Email");
     }
@@ -1439,7 +1476,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Create expected schemaType proto.
         SchemaProto expectedProto =
@@ -1472,8 +1510,8 @@
                         /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                         /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                         /*forceOverride=*/ false,
-                        /*version=*/ 0);
-
+                        /*version=*/ 0,
+                        /* setSchemaStatsBuilder= */ null);
         // Check the Document type has been deleted.
         assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Document");
 
@@ -1486,7 +1524,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ true,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Check Document schema is removed.
         expectedProto =
@@ -1524,7 +1563,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "package",
                 "database2",
@@ -1533,7 +1573,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Create expected schemaType proto.
         SchemaProto expectedProto =
@@ -1573,7 +1614,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ true,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Create expected schemaType list, database 1 should only contain Email but database 2
         // remains in same.
@@ -1618,7 +1660,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert package document
         GenericDocument document =
@@ -1680,7 +1723,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "packageB",
                 "database",
@@ -1689,7 +1733,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Verify these two packages is stored in AppSearch
         SchemaProto expectedProto =
@@ -1735,7 +1780,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         assertThat(mAppSearchImpl.getPackageToDatabases())
                 .containsExactlyEntriesIn(expectedMapping);
 
@@ -1749,7 +1795,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         assertThat(mAppSearchImpl.getPackageToDatabases())
                 .containsExactlyEntriesIn(expectedMapping);
 
@@ -1763,7 +1810,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         assertThat(mAppSearchImpl.getPackageToDatabases())
                 .containsExactlyEntriesIn(expectedMapping);
     }
@@ -1822,7 +1870,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two docs
         GenericDocument document1 =
@@ -1973,7 +2022,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Since "package1" doesn't have a document, it get any space attributed to it.
         StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForPackage("package1");
@@ -1996,7 +2046,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert document for "package1"
         GenericDocument document =
@@ -2012,7 +2063,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert two documents for "package2"
         document = new GenericDocument.Builder<>("namespace", "id1", "type").build();
@@ -2061,7 +2113,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // "package2" doesn't exist yet, so it shouldn't have any storage size
         StorageInfo storageInfo =
@@ -2084,7 +2137,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Since "package1", "database1" doesn't have a document, it get any space attributed to it.
         StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForDatabase("package1", "database1");
@@ -2106,7 +2160,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "package1",
                 "database2",
@@ -2115,7 +2170,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Add a document for "package1", "database1"
         GenericDocument document =
@@ -2165,7 +2221,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         appSearchImpl.close();
 
@@ -2181,7 +2238,8 @@
                                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                                 /*forceOverride=*/ false,
-                                /*version=*/ 0));
+                                /*version=*/ 0,
+                                /* setSchemaStatsBuilder= */ null));
 
         assertThrows(
                 IllegalStateException.class, () -> appSearchImpl.getSchema("package", "database"));
@@ -2225,7 +2283,9 @@
 
         assertThrows(
                 IllegalStateException.class,
-                () -> appSearchImpl.getNextPage("package", /*nextPageToken=*/ 1L));
+                () ->
+                        appSearchImpl.getNextPage(
+                                "package", /*nextPageToken=*/ 1L, /*statsBuilder=*/ null));
 
         assertThrows(
                 IllegalStateException.class,
@@ -2296,7 +2356,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Add a document and persist it.
         GenericDocument document =
@@ -2343,7 +2404,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Add two documents and persist them.
         GenericDocument document1 =
@@ -2423,7 +2485,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Add two documents and persist them.
         GenericDocument document1 =
@@ -2511,7 +2574,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Add two documents
         GenericDocument document1 =
@@ -2562,7 +2626,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert a document which is too large
         GenericDocument document =
@@ -2636,7 +2701,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Index a document
         mAppSearchImpl.putDocument(
@@ -2723,7 +2789,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Index 3 documents
         mAppSearchImpl.putDocument(
@@ -2836,7 +2903,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "package1",
                 "database2",
@@ -2845,7 +2913,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "package2",
                 "database1",
@@ -2854,7 +2923,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         mAppSearchImpl.setSchema(
                 "package2",
                 "database2",
@@ -2863,7 +2933,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Index documents in package1/database1
         mAppSearchImpl.putDocument(
@@ -3002,7 +3073,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Index 3 documents
         mAppSearchImpl.putDocument(
@@ -3131,7 +3203,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Index a document
         mAppSearchImpl.putDocument(
@@ -3210,7 +3283,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Index a document
         mAppSearchImpl.putDocument(
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index 7c97687..2ab5fd5 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -33,6 +33,7 @@
 import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
 import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
 import com.android.server.appsearch.icing.proto.DeleteStatsProto;
 import com.android.server.appsearch.icing.proto.DocumentProto;
 import com.android.server.appsearch.icing.proto.InitializeStatsProto;
@@ -41,6 +42,7 @@
 import com.android.server.appsearch.icing.proto.PutResultProto;
 import com.android.server.appsearch.icing.proto.QueryStatsProto;
 import com.android.server.appsearch.icing.proto.ScoringSpecProto;
+import com.android.server.appsearch.icing.proto.SetSchemaResultProto;
 import com.android.server.appsearch.icing.proto.StatusProto;
 import com.android.server.appsearch.icing.proto.TermMatchType;
 
@@ -57,14 +59,17 @@
 import java.util.List;
 
 public class AppSearchLoggerTest {
-    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
-    private AppSearchImpl mAppSearchImpl;
-    private TestLogger mLogger;
+    private static final String PACKAGE_NAME = "packageName";
+    private static final String DATABASE = "database";
     /**
      * Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
      */
     private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
 
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+    private AppSearchImpl mAppSearchImpl;
+    private TestLogger mLogger;
+
     @Before
     public void setUp() throws Exception {
         mAppSearchImpl =
@@ -84,6 +89,7 @@
         @Nullable SearchStats mSearchStats;
         @Nullable RemoveStats mRemoveStats;
         @Nullable OptimizeStats mOptimizeStats;
+        @Nullable SetSchemaStats mSetSchemaStats;
 
         @Override
         public void logStats(@NonNull CallStats stats) {
@@ -114,6 +120,11 @@
         public void logStats(@NonNull OptimizeStats stats) {
             mOptimizeStats = stats;
         }
+
+        @Override
+        public void logStats(@NonNull SetSchemaStats stats) {
+            mSetSchemaStats = stats;
+        }
     }
 
     @Test
@@ -194,7 +205,7 @@
                                         .setExceededMaxTokenNum(nativeExceededMaxNumTokens)
                                         .build())
                         .build();
-        PutDocumentStats.Builder pBuilder = new PutDocumentStats.Builder("packageName", "database");
+        PutDocumentStats.Builder pBuilder = new PutDocumentStats.Builder(PACKAGE_NAME, DATABASE);
 
         AppSearchLoggerHelper.copyNativeStats(nativePutDocumentStats, pBuilder);
 
@@ -248,8 +259,8 @@
                         .setDocumentRetrievalLatencyMs(nativeDocumentRetrievingLatencyMillis)
                         .build();
         SearchStats.Builder qBuilder =
-                new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, "packageName")
-                        .setDatabase("database");
+                new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, PACKAGE_NAME)
+                        .setDatabase(DATABASE);
 
         AppSearchLoggerHelper.copyNativeStats(nativeQueryStats, qBuilder);
 
@@ -336,6 +347,35 @@
                 .isEqualTo(nativeTimeSinceLastOptimizeMillis);
     }
 
+    @Test
+    public void testAppSearchLoggerHelper_testCopyNativeStats_setSchema() {
+        ImmutableList<String> newSchemaTypeChangeList = ImmutableList.of("new1");
+        ImmutableList<String> deletedSchemaTypesList = ImmutableList.of("deleted1", "deleted2");
+        ImmutableList<String> compatibleTypesList = ImmutableList.of("compatible1", "compatible2");
+        ImmutableList<String> indexIncompatibleTypeChangeList = ImmutableList.of("index1");
+        ImmutableList<String> backwardsIncompatibleTypeChangeList = ImmutableList.of("backwards1");
+        SetSchemaResultProto setSchemaResultProto =
+                SetSchemaResultProto.newBuilder()
+                        .addAllNewSchemaTypes(newSchemaTypeChangeList)
+                        .addAllDeletedSchemaTypes(deletedSchemaTypesList)
+                        .addAllFullyCompatibleChangedSchemaTypes(compatibleTypesList)
+                        .addAllIndexIncompatibleChangedSchemaTypes(indexIncompatibleTypeChangeList)
+                        .addAllIncompatibleSchemaTypes(backwardsIncompatibleTypeChangeList)
+                        .build();
+        SetSchemaStats.Builder sBuilder = new SetSchemaStats.Builder(PACKAGE_NAME, DATABASE);
+
+        AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto, sBuilder);
+
+        SetSchemaStats sStats = sBuilder.build();
+        assertThat(sStats.getNewTypeCount()).isEqualTo(newSchemaTypeChangeList.size());
+        assertThat(sStats.getDeletedTypeCount()).isEqualTo(deletedSchemaTypesList.size());
+        assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypesList.size());
+        assertThat(sStats.getIndexIncompatibleTypeChangeCount())
+                .isEqualTo(indexIncompatibleTypeChangeList.size());
+        assertThat(sStats.getBackwardsIncompatibleTypeChangeCount())
+                .isEqualTo(backwardsIncompatibleTypeChangeList.size());
+    }
+
     //
     // Testing actual logging
     //
@@ -388,7 +428,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
         GenericDocument doc2 = new GenericDocument.Builder<>("namespace", "id2", "Type1").build();
         appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger);
@@ -439,7 +480,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         // Insert a valid doc
         GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
@@ -495,7 +537,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         GenericDocument document =
                 new GenericDocument.Builder<>("namespace", "id", "type")
@@ -542,7 +585,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         GenericDocument document =
                 new GenericDocument.Builder<>("namespace", "id", "type")
@@ -592,7 +636,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         GenericDocument document1 =
                 new GenericDocument.Builder<>("namespace", "id1", "type")
                         .setPropertyString("subject", "testPut example1")
@@ -661,7 +706,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         SearchSpec searchSpec =
                 new SearchSpec.Builder()
@@ -701,7 +747,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         GenericDocument document =
                 new GenericDocument.Builder<>(testNamespace, testId, "type").build();
         mAppSearchImpl.putDocument(testPackageName, testDatabase, document, /*logger=*/ null);
@@ -735,7 +782,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
 
         GenericDocument document =
                 new GenericDocument.Builder<>(testNamespace, testId, "type").build();
@@ -780,7 +828,8 @@
                 /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
                 /*schemasVisibleToPackages=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false,
-                /*version=*/ 0);
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
         GenericDocument document1 =
                 new GenericDocument.Builder<>(testNamespace, "id1", "type").build();
         GenericDocument document2 =
@@ -800,7 +849,58 @@
         assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
         assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
         // delete by query
-        assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.QUERY_VALUE);
+        assertThat(rStats.getDeleteType())
+                .isEqualTo(DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY_VALUE);
         assertThat(rStats.getDeletedDocumentCount()).isEqualTo(2);
     }
+
+    @Test
+    public void testLoggingStats_setSchema() throws Exception {
+        AppSearchSchema schema1 =
+                new AppSearchSchema.Builder("testSchema")
+                        .addProperty(
+                                new AppSearchSchema.StringPropertyConfig.Builder("subject")
+                                        .setCardinality(
+                                                AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+                                        .setIndexingType(
+                                                AppSearchSchema.StringPropertyConfig
+                                                        .INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(
+                                                AppSearchSchema.StringPropertyConfig
+                                                        .TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        mAppSearchImpl.setSchema(
+                PACKAGE_NAME,
+                DATABASE,
+                Collections.singletonList(schema1),
+                /*visibilityStore=*/ null,
+                /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+                /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+                /*forceOverride=*/ false,
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ null);
+
+        // create a backwards incompatible schema
+        SetSchemaStats.Builder sStatsBuilder = new SetSchemaStats.Builder(PACKAGE_NAME, DATABASE);
+        AppSearchSchema schema2 = new AppSearchSchema.Builder("testSchema").build();
+        mAppSearchImpl.setSchema(
+                PACKAGE_NAME,
+                DATABASE,
+                Collections.singletonList(schema2),
+                /*visibilityStore=*/ null,
+                /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+                /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+                /*forceOverride=*/ false,
+                /*version=*/ 0,
+                /* setSchemaStatsBuilder= */ sStatsBuilder);
+
+        SetSchemaStats sStats = sStatsBuilder.build();
+        assertThat(sStats.getPackageName()).isEqualTo(PACKAGE_NAME);
+        assertThat(sStats.getDatabase()).isEqualTo(DATABASE);
+        assertThat(sStats.getNewTypeCount()).isEqualTo(0);
+        assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(0);
+        assertThat(sStats.getIndexIncompatibleTypeChangeCount()).isEqualTo(1);
+        assertThat(sStats.getBackwardsIncompatibleTypeChangeCount()).isEqualTo(1);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index c1dc0e4..81aab41 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -264,17 +264,15 @@
                         .setMigratedDocumentCount(6)
                         .setSavedDocumentCount(7)
                         .build();
-        int nativeLatencyMillis = 1;
-        int newTypeCount = 2;
-        int compatibleTypeChangeCount = 3;
-        int indexIncompatibleTypeChangeCount = 4;
-        int backwardsIncompatibleTypeChangeCount = 5;
+        int newTypeCount = 1;
+        int compatibleTypeChangeCount = 2;
+        int indexIncompatibleTypeChangeCount = 3;
+        int backwardsIncompatibleTypeChangeCount = 4;
         SetSchemaStats sStats =
                 new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
                         .setStatusCode(TEST_STATUS_CODE)
                         .setSchemaMigrationStats(schemaMigrationStats)
                         .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
-                        .setNativeLatencyMillis(nativeLatencyMillis)
                         .setNewTypeCount(newTypeCount)
                         .setCompatibleTypeChangeCount(compatibleTypeChangeCount)
                         .setIndexIncompatibleTypeChangeCount(indexIncompatibleTypeChangeCount)
@@ -287,7 +285,6 @@
         assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
         assertThat(sStats.getSchemaMigrationStats()).isEqualTo(schemaMigrationStats);
         assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
-        assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
         assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount);
         assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypeChangeCount);
         assertThat(sStats.getIndexIncompatibleTypeChangeCount())
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 2892bf5..b3f7587 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -74,6 +74,7 @@
 public class AuthSessionTest {
 
     private static final String TEST_PACKAGE = "test_package";
+    private static final long TEST_REQUEST_ID = 22;
 
     @Mock private Context mContext;
     @Mock private ITrustManager mTrustManager;
@@ -112,6 +113,7 @@
         final AuthSession session = createAuthSession(mSensors,
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
+                TEST_REQUEST_ID,
                 0 /* operationId */,
                 0 /* userId */);
 
@@ -133,6 +135,7 @@
         final AuthSession session = createAuthSession(mSensors,
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
+                TEST_REQUEST_ID,
                 operationId,
                 userId);
         assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
@@ -153,6 +156,7 @@
                     eq(userId),
                     eq(mSensorReceiver),
                     eq(TEST_PACKAGE),
+                    eq(TEST_REQUEST_ID),
                     eq(sensor.getCookie()),
                     anyBoolean() /* allowBackgroundAuthentication */);
         }
@@ -185,6 +189,33 @@
     }
 
     @Test
+    public void testCancelReducesAppetiteForCookies() throws Exception {
+        setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
+                mock(IBiometricAuthenticator.class));
+        setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+
+        final AuthSession session = createAuthSession(mSensors,
+                false /* checkDevicePolicyManager */,
+                Authenticators.BIOMETRIC_STRONG,
+                TEST_REQUEST_ID,
+                44 /* operationId */,
+                2 /* userId */);
+
+        session.goToInitialState();
+
+        for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+            assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
+        }
+
+        session.onCancelAuthSession(false /* force */);
+
+        for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+            session.onCookieReceived(sensor.getCookie());
+            assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState());
+        }
+    }
+
+    @Test
     public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()
             throws Exception {
         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
@@ -212,6 +243,7 @@
         final AuthSession session = createAuthSession(mSensors,
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
+                TEST_REQUEST_ID,
                 operationId,
                 userId);
         assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
@@ -238,7 +270,7 @@
         // fingerprint sensor does not start even if all cookies are received
         assertEquals(STATE_AUTH_STARTED, session.getState());
         verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
-                anyBoolean(), anyBoolean(), anyInt(), any(), anyLong(), anyInt());
+                anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong(), anyInt());
 
         // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started.
         session.onDialogAnimatedIn();
@@ -277,6 +309,7 @@
         final AuthSession session = createAuthSession(mSensors,
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
+                TEST_REQUEST_ID,
                 0 /* operationId */,
                 0 /* userId */);
 
@@ -285,7 +318,8 @@
 
         sessionConsumer.accept(session);
 
-        verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE));
+        verify(faceAuthenticator).cancelAuthenticationFromService(
+                eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID));
     }
 
     private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId,
@@ -302,14 +336,14 @@
 
     private AuthSession createAuthSession(List<BiometricSensor> sensors,
             boolean checkDevicePolicyManager, @Authenticators.Types int authenticators,
-            long operationId, int userId) throws RemoteException {
+            long requestId, long operationId, int userId) throws RemoteException {
 
         final PromptInfo promptInfo = createPromptInfo(authenticators);
 
         final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo,
                 checkDevicePolicyManager);
         return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore,
-                mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId,
+                mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, operationId, userId,
                 mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
                 false /* debugEnabled */, mFingerprintSensorProps);
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 7c7afb7..69d8e89 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -85,6 +85,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicLong;
 
 @Presubmit
 @SmallTest
@@ -93,6 +94,7 @@
     private static final String TAG = "BiometricServiceTest";
 
     private static final String TEST_PACKAGE_NAME = "test_package";
+    private static final long TEST_REQUEST_ID = 44;
 
     private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable";
     private static final String ERROR_NOT_RECOGNIZED = "not_recognized";
@@ -151,6 +153,7 @@
                 .thenReturn(mock(BiometricStrengthController.class));
         when(mInjector.getTrustManager()).thenReturn(mTrustManager);
         when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager);
+        when(mInjector.getRequestGenerator()).thenReturn(new AtomicLong(TEST_REQUEST_ID - 1));
 
         when(mResources.getString(R.string.biometric_error_hw_unavailable))
                 .thenReturn(ERROR_HW_UNAVAILABLE);
@@ -215,8 +218,7 @@
                 mBiometricService.mCurrentAuthSession.getState());
 
         verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl)
-                .cancelAuthenticationFromService(any(),
-                        any());
+                .cancelAuthenticationFromService(any(), any(), anyLong());
 
         // Simulate ERROR_CANCELED received from HAL
         mBiometricService.mBiometricSensorReceiver.onError(
@@ -272,8 +274,9 @@
                 eq(true) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(TEST_REQUEST_ID),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -357,8 +360,9 @@
                 eq(false) /* credentialAllowed */,
                 eq(false) /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(TEST_REQUEST_ID),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -467,6 +471,7 @@
                 anyInt() /* userId */,
                 any(IBiometricSensorReceiver.class),
                 anyString() /* opPackageName */,
+                eq(TEST_REQUEST_ID),
                 cookieCaptor.capture() /* cookie */,
                 anyBoolean() /* allowBackgroundAuthentication */);
 
@@ -488,8 +493,9 @@
                 eq(false) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(TEST_REQUEST_ID),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
 
         // Hardware authenticated
@@ -543,8 +549,9 @@
                 eq(true) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(TEST_REQUEST_ID),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -705,8 +712,9 @@
                 anyBoolean() /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 anyString(),
-                anyLong() /* sessionId */,
+                anyLong() /* requestId */,
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -805,8 +813,9 @@
                 eq(true) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(TEST_REQUEST_ID),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -885,8 +894,9 @@
                 eq(true) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(TEST_REQUEST_ID),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -1030,8 +1040,7 @@
                 eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
                 eq(0 /* vendorCode */));
         verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService(
-                any(),
-                any());
+                any(), any(), anyLong());
         assertNull(mBiometricService.mCurrentAuthSession);
     }
 
@@ -1051,7 +1060,7 @@
         waitForIdle();
 
         verify(mBiometricService.mSensors.get(0).impl)
-                .cancelAuthenticationFromService(any(), any());
+                .cancelAuthenticationFromService(any(), any(), anyLong());
     }
 
     @Test
@@ -1071,7 +1080,7 @@
         waitForIdle();
 
         verify(mBiometricService.mSensors.get(0).impl)
-                .cancelAuthenticationFromService(any(), any());
+                .cancelAuthenticationFromService(any(), any(), anyLong());
     }
 
     @Test
@@ -1088,7 +1097,7 @@
         waitForIdle();
 
         verify(mBiometricService.mSensors.get(0).impl)
-                .cancelAuthenticationFromService(any(), any());
+                .cancelAuthenticationFromService(any(), any(), anyLong());
         verify(mReceiver1).onError(
                 eq(BiometricAuthenticator.TYPE_FACE),
                 eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
@@ -1126,7 +1135,7 @@
                 false /* requireConfirmation */, null /* authenticators */);
 
         mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken,
-                TEST_PACKAGE_NAME);
+                TEST_PACKAGE_NAME, TEST_REQUEST_ID);
         waitForIdle();
 
         // Pretend that the HAL has responded to cancel with ERROR_CANCELED
@@ -1353,8 +1362,8 @@
         int authenticators = Authenticators.BIOMETRIC_STRONG;
         assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
                 invokeCanAuthenticate(mBiometricService, authenticators));
-        invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
-                authenticators);
+        long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
+                false /* requireConfirmation */, authenticators);
         waitForIdle();
         verify(mReceiver1).onError(
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -1366,7 +1375,7 @@
         authenticators = Authenticators.BIOMETRIC_WEAK;
         assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
                 invokeCanAuthenticate(mBiometricService, authenticators));
-        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+        requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                 false /* requireConfirmation */,
                 authenticators);
         waitForIdle();
@@ -1377,8 +1386,9 @@
                 eq(false) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(requestId),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
 
         // Requesting strong and credential, when credential is setup
@@ -1387,7 +1397,7 @@
         when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
         assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
                 invokeCanAuthenticate(mBiometricService, authenticators));
-        invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
+        requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
                 false /* requireConfirmation */,
                 authenticators);
         waitForIdle();
@@ -1399,8 +1409,9 @@
                 eq(true) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(requestId),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
 
         // Un-downgrading the authenticator allows successful strong auth
@@ -1414,7 +1425,7 @@
         authenticators = Authenticators.BIOMETRIC_STRONG;
         assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
                 invokeCanAuthenticate(mBiometricService, authenticators));
-        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+        requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                 false /* requireConfirmation */, authenticators);
         waitForIdle();
         verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
@@ -1424,8 +1435,9 @@
                 eq(false) /* credentialAllowed */,
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
+                anyLong() /* operationId */,
                 eq(TEST_PACKAGE_NAME),
-                anyLong() /* sessionId */,
+                eq(requestId),
                 eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
     }
 
@@ -1617,11 +1629,12 @@
         mBiometricService.mStatusBarService = mock(IStatusBarService.class);
     }
 
-    private void invokeAuthenticateAndStart(IBiometricService.Stub service,
+    private long invokeAuthenticateAndStart(IBiometricService.Stub service,
             IBiometricServiceReceiver receiver, boolean requireConfirmation,
             Integer authenticators) throws Exception {
         // Request auth, creates a pending session
-        invokeAuthenticate(service, receiver, requireConfirmation, authenticators);
+        final long requestId = invokeAuthenticate(
+                service, receiver, requireConfirmation, authenticators);
         waitForIdle();
 
         startPendingAuthSession(mBiometricService);
@@ -1629,6 +1642,8 @@
 
         assertNotNull(mBiometricService.mCurrentAuthSession);
         assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
+
+        return requestId;
     }
 
     private static void startPendingAuthSession(BiometricService service) throws Exception {
@@ -1644,10 +1659,10 @@
         service.mImpl.onReadyForAuthentication(cookie);
     }
 
-    private static void invokeAuthenticate(IBiometricService.Stub service,
+    private static long invokeAuthenticate(IBiometricService.Stub service,
             IBiometricServiceReceiver receiver, boolean requireConfirmation,
             Integer authenticators) throws Exception {
-        service.authenticate(
+        return service.authenticate(
                 new Binder() /* token */,
                 0 /* operationId */,
                 0 /* userId */,
@@ -1657,9 +1672,9 @@
                         false /* checkDevicePolicy */));
     }
 
-    private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service,
+    private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service,
             IBiometricServiceReceiver receiver, Integer authenticators) throws Exception {
-        service.authenticate(
+        return service.authenticate(
                 new Binder() /* token */,
                 0 /* operationId */,
                 0 /* userId */,
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 f4d1499..e3e3900 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
@@ -40,6 +40,7 @@
 import android.testing.TestableContext;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
@@ -193,7 +194,7 @@
         // Request it to be canceled. The operation can be canceled immediately, and the scheduler
         // should go back to idle, since in this case the framework has not even requested the HAL
         // to authenticate yet.
-        mScheduler.cancelAuthenticationOrDetection(mToken);
+        mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
         assertNull(mScheduler.mCurrentOperation);
     }
 
@@ -303,7 +304,7 @@
                 mScheduler.mPendingOperations.getFirst().mState);
 
         // Request cancel before the authentication client has started
-        mScheduler.cancelAuthenticationOrDetection(mToken);
+        mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
         waitForIdle();
         assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING,
                 mScheduler.mPendingOperations.getFirst().mState);
@@ -318,6 +319,107 @@
     }
 
     @Test
+    public void testCancels_whenAuthRequestIdNotSet() {
+        testCancelsWhenRequestId(null /* requestId */, 2, true /* started */);
+    }
+
+    @Test
+    public void testCancels_whenAuthRequestIdNotSet_notStarted() {
+        testCancelsWhenRequestId(null /* requestId */, 2, false /* started */);
+    }
+
+    @Test
+    public void testCancels_whenAuthRequestIdMatches() {
+        testCancelsWhenRequestId(200L, 200, true /* started */);
+    }
+
+    @Test
+    public void testCancels_whenAuthRequestIdMatches_noStarted() {
+        testCancelsWhenRequestId(200L, 200, false /* started */);
+    }
+
+    @Test
+    public void testDoesNotCancel_whenAuthRequestIdMismatched() {
+        testCancelsWhenRequestId(10L, 20, true /* started */);
+    }
+
+    @Test
+    public void testDoesNotCancel_whenAuthRequestIdMismatched_notStarted() {
+        testCancelsWhenRequestId(10L, 20, false /* started */);
+    }
+
+    private void testCancelsWhenRequestId(@Nullable Long requestId, long cancelRequestId,
+            boolean started) {
+        final boolean matches = requestId == null || requestId == cancelRequestId;
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class);
+        final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
+        final TestAuthenticationClient client = new TestAuthenticationClient(
+                mContext, lazyDaemon, mToken, callback);
+        if (requestId != null) {
+            client.setRequestId(requestId);
+        }
+
+        mScheduler.scheduleClientMonitor(client);
+        if (started) {
+            mScheduler.startPreparedClient(client.getCookie());
+        }
+        waitForIdle();
+        mScheduler.cancelAuthenticationOrDetection(mToken, cancelRequestId);
+        waitForIdle();
+
+        assertEquals(matches && started ? 1 : 0, client.mNumCancels);
+
+        if (matches) {
+            if (started) {
+                assertEquals(Operation.STATE_STARTED_CANCELING,
+                        mScheduler.mCurrentOperation.mState);
+            }
+        } else {
+            if (started) {
+                assertEquals(Operation.STATE_STARTED,
+                        mScheduler.mCurrentOperation.mState);
+            } else {
+                assertEquals(Operation.STATE_WAITING_FOR_COOKIE,
+                        mScheduler.mCurrentOperation.mState);
+            }
+        }
+    }
+
+    @Test
+    public void testCancelsPending_whenAuthRequestIdsSet() {
+        final long requestId1 = 10;
+        final long requestId2 = 20;
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class);
+        final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
+        final TestAuthenticationClient client1 = new TestAuthenticationClient(
+                mContext, lazyDaemon, mToken, callback);
+        client1.setRequestId(requestId1);
+        final TestAuthenticationClient client2 = new TestAuthenticationClient(
+                mContext, lazyDaemon, mToken, callback);
+        client2.setRequestId(requestId2);
+
+        mScheduler.scheduleClientMonitor(client1);
+        mScheduler.scheduleClientMonitor(client2);
+        mScheduler.startPreparedClient(client1.getCookie());
+        waitForIdle();
+        mScheduler.cancelAuthenticationOrDetection(mToken, 9999);
+        waitForIdle();
+
+        assertEquals(Operation.STATE_STARTED,
+                mScheduler.mCurrentOperation.mState);
+        assertEquals(Operation.STATE_WAITING_IN_QUEUE,
+                mScheduler.mPendingOperations.getFirst().mState);
+
+        mScheduler.cancelAuthenticationOrDetection(mToken, requestId2);
+        waitForIdle();
+
+        assertEquals(Operation.STATE_STARTED,
+                mScheduler.mCurrentOperation.mState);
+        assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING,
+                mScheduler.mPendingOperations.getFirst().mState);
+    }
+
+    @Test
     public void testInterruptPrecedingClients_whenExpected() {
         final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
                 withSettings().extraInterfaces(Interruptable.class));
@@ -348,6 +450,17 @@
         verify((Interruptable) interruptableMonitor, never()).cancel();
     }
 
+    @Test
+    public void testClientDestroyed_afterFinish() {
+        final HalClientMonitor.LazyDaemon<Object> nonNullDaemon = () -> mock(Object.class);
+        final TestClientMonitor client =
+                new TestClientMonitor(mContext, mToken, nonNullDaemon);
+        mScheduler.scheduleClientMonitor(client);
+        client.mCallback.onClientFinished(client, true /* success */);
+        waitForIdle();
+        assertTrue(client.wasDestroyed());
+    }
+
     private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception {
         return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
     }
@@ -366,12 +479,10 @@
 
         @Override
         protected void stopHalOperation() {
-
         }
 
         @Override
         protected void startHalOperation() {
-
         }
 
         @Override
@@ -386,6 +497,7 @@
     }
 
     private static class TestAuthenticationClient extends AuthenticationClient<Object> {
+        int mNumCancels = 0;
 
         public TestAuthenticationClient(@NonNull Context context,
                 @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
@@ -417,6 +529,11 @@
         public boolean wasUserDetected() {
             return false;
         }
+
+        public void cancel() {
+            mNumCancels++;
+            super.cancel();
+        }
     }
 
     private static class TestClientMonitor2 extends TestClientMonitor {
@@ -437,6 +554,7 @@
     private static class TestClientMonitor extends HalClientMonitor<Object> {
         private boolean mUnableToStart;
         private boolean mStarted;
+        private boolean mDestroyed;
 
         public TestClientMonitor(@NonNull Context context, @NonNull IBinder token,
                 @NonNull LazyDaemon<Object> lazyDaemon) {
@@ -475,6 +593,11 @@
 
         }
 
+        @Override
+        public void destroy() {
+            mDestroyed = true;
+        }
+
         public boolean wasUnableToStart() {
             return mUnableToStart;
         }
@@ -482,6 +605,11 @@
         public boolean hasStarted() {
             return mStarted;
         }
+
+        public boolean wasDestroyed() {
+            return mDestroyed;
+        }
+
     }
 
     private static void waitForIdle() {
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index ff8fbda..b1b6e53 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
 
+import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
@@ -35,6 +36,11 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import static org.mockito.Mockito.mock;
+
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.WindowProcessController;
+
 import junit.framework.Assert;
 
 import org.junit.Before;
@@ -55,10 +61,15 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public final class DeviceStateManagerServiceTest {
-    private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(0, "DEFAULT");
-    private static final DeviceState OTHER_DEVICE_STATE = new DeviceState(1, "OTHER");
+    private static final DeviceState DEFAULT_DEVICE_STATE =
+            new DeviceState(0, "DEFAULT", 0 /* flags */);
+    private static final DeviceState OTHER_DEVICE_STATE =
+            new DeviceState(1, "OTHER", 0 /* flags */);
     // A device state that is not reported as being supported for the default test provider.
-    private static final DeviceState UNSUPPORTED_DEVICE_STATE = new DeviceState(255, "UNSUPPORTED");
+    private static final DeviceState UNSUPPORTED_DEVICE_STATE =
+            new DeviceState(255, "UNSUPPORTED", 0 /* flags */);
+
+    private static final int FAKE_PROCESS_ID = 100;
 
     private TestDeviceStatePolicy mPolicy;
     private TestDeviceStateProvider mProvider;
@@ -69,6 +80,25 @@
         mProvider = new TestDeviceStateProvider();
         mPolicy = new TestDeviceStatePolicy(mProvider);
         mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy);
+
+        // Necessary to allow us to check for top app process id in tests
+        mService.mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
+        WindowProcessController windowProcessController = mock(WindowProcessController.class);
+        when(mService.mActivityTaskManagerInternal.getTopApp())
+                .thenReturn(windowProcessController);
+        when(windowProcessController.getPid()).thenReturn(FAKE_PROCESS_ID);
+
+        flushHandler(); // Flush the handler to ensure the initial values are committed.
+    }
+
+    private void flushHandler() {
+        flushHandler(1);
+    }
+
+    private void flushHandler(int count) {
+        for (int i = 0; i < count; i++) {
+            mService.getHandler().runWithScissors(() -> {}, 0);
+        }
     }
 
     @Test
@@ -80,6 +110,7 @@
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        flushHandler();
         assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
         assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
@@ -92,6 +123,7 @@
         mPolicy.blockConfigure();
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        flushHandler();
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
@@ -99,6 +131,7 @@
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
+        flushHandler();
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
@@ -106,6 +139,7 @@
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
+        flushHandler();
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
@@ -149,6 +183,7 @@
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
+        flushHandler();
 
         // The current committed and requests states do not change because the current state remains
         // supported.
@@ -166,6 +201,7 @@
         mService.getBinderService().registerCallback(callback);
 
         // An initial callback will be triggered on registration, so we clear it here.
+        flushHandler();
         callback.clearLastNotifiedInfo();
 
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
@@ -174,6 +210,7 @@
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
                 OTHER_DEVICE_STATE });
+        flushHandler();
 
         // The current committed and requests states do not change because the current state remains
         // supported.
@@ -203,12 +240,14 @@
         mService.getBinderService().registerCallback(callback);
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        flushHandler();
         assertEquals(callback.getLastNotifiedInfo().baseState,
                 OTHER_DEVICE_STATE.getIdentifier());
         assertEquals(callback.getLastNotifiedInfo().currentState,
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
+        flushHandler();
         assertEquals(callback.getLastNotifiedInfo().baseState,
                 DEFAULT_DEVICE_STATE.getIdentifier());
         assertEquals(callback.getLastNotifiedInfo().currentState,
@@ -216,6 +255,7 @@
 
         mPolicy.blockConfigure();
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        flushHandler();
         // The callback should not have been notified of the state change as the policy is still
         // pending callback.
         assertEquals(callback.getLastNotifiedInfo().baseState,
@@ -224,6 +264,7 @@
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
+        flushHandler();
         // Now that the policy is finished processing the callback should be notified of the state
         // change.
         assertEquals(callback.getLastNotifiedInfo().baseState,
@@ -236,6 +277,7 @@
     public void registerCallback_emitsInitialValue() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
+        flushHandler();
         assertNotNull(callback.getLastNotifiedInfo());
         assertEquals(callback.getLastNotifiedInfo().baseState,
                 DEFAULT_DEVICE_STATE.getIdentifier());
@@ -247,6 +289,7 @@
     public void requestState() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
+        flushHandler();
 
         final IBinder token = new Binder();
         assertEquals(callback.getLastNotifiedStatus(token),
@@ -254,6 +297,10 @@
 
         mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
                 0 /* flags */);
+        // Flush the handler twice. The first flush ensures the request is added and the policy is
+        // notified, while the second flush ensures the callback is notified once the change is
+        // committed.
+        flushHandler(2 /* count */);
 
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
@@ -271,6 +318,7 @@
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mService.getBinderService().cancelRequest(token);
+        flushHandler();
 
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
@@ -291,6 +339,7 @@
     public void requestState_pendingStateAtRequest() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
+        flushHandler();
 
         mPolicy.blockConfigure();
 
@@ -303,6 +352,10 @@
 
         mService.getBinderService().requestState(firstRequestToken,
                 OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+        // Flush the handler twice. The first flush ensures the request is added and the policy is
+        // notified, while the second flush ensures the callback is notified once the change is
+        // committed.
+        flushHandler(2 /* count */);
 
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
@@ -312,8 +365,8 @@
 
         mService.getBinderService().requestState(secondRequestToken,
                 DEFAULT_DEVICE_STATE.getIdentifier(), 0 /* flags */);
-
         mPolicy.resumeConfigureOnce();
+        flushHandler();
 
         // First request status is now suspended as there is another pending request.
         assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
@@ -330,6 +383,7 @@
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
+        flushHandler();
 
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
@@ -339,6 +393,7 @@
 
         // Now cancel the second request to make the first request active.
         mService.getBinderService().cancelRequest(secondRequestToken);
+        flushHandler();
 
         assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
@@ -356,6 +411,7 @@
     public void requestState_sameAsBaseState() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
+        flushHandler();
 
         final IBinder token = new Binder();
         assertEquals(callback.getLastNotifiedStatus(token),
@@ -363,6 +419,7 @@
 
         mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
                 0 /* flags */);
+        flushHandler();
 
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
@@ -372,6 +429,7 @@
     public void requestState_flagCancelWhenBaseChanges() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
+        flushHandler();
 
         final IBinder token = new Binder();
         assertEquals(callback.getLastNotifiedStatus(token),
@@ -379,6 +437,10 @@
 
         mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
                 DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES);
+        // Flush the handler twice. The first flush ensures the request is added and the policy is
+        // notified, while the second flush ensures the callback is notified once the change is
+        // committed.
+        flushHandler(2 /* count */);
 
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
@@ -391,6 +453,7 @@
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        flushHandler();
 
         // Request is canceled because the base state changed.
         assertEquals(callback.getLastNotifiedStatus(token),
@@ -407,6 +470,7 @@
     public void requestState_becomesUnsupported() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
+        flushHandler();
 
         final IBinder token = new Binder();
         assertEquals(callback.getLastNotifiedStatus(token),
@@ -414,6 +478,7 @@
 
         mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
                 0 /* flags */);
+        flushHandler();
 
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
@@ -425,6 +490,7 @@
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
+        flushHandler();
 
         // Request is canceled because the state is no longer supported.
         assertEquals(callback.getLastNotifiedStatus(token),
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateTest.java
index b5c8053..e286cb2 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateTest.java
@@ -41,24 +41,26 @@
     @Test
     public void testConstruct() {
         final DeviceState state = new DeviceState(MINIMUM_DEVICE_STATE /* identifier */,
-                "CLOSED" /* name */);
+                "CLOSED" /* name */, DeviceState.FLAG_CANCEL_STICKY_REQUESTS /* flags */);
         assertEquals(state.getIdentifier(), MINIMUM_DEVICE_STATE);
         assertEquals(state.getName(), "CLOSED");
+        assertEquals(state.getFlags(), DeviceState.FLAG_CANCEL_STICKY_REQUESTS);
     }
 
     @Test
     public void testConstruct_nullName() {
         final DeviceState state = new DeviceState(MAXIMUM_DEVICE_STATE /* identifier */,
-                null /* name */);
+                null /* name */, 0/* flags */);
         assertEquals(state.getIdentifier(), MAXIMUM_DEVICE_STATE);
         assertNull(state.getName());
+        assertEquals(state.getFlags(), 0);
     }
 
     @Test
     public void testConstruct_tooLargeIdentifier() {
         assertThrows(IllegalArgumentException.class, () -> {
             final DeviceState state = new DeviceState(MAXIMUM_DEVICE_STATE + 1 /* identifier */,
-                    null /* name */);
+                    null /* name */, 0 /* flags */);
         });
     }
 
@@ -66,7 +68,7 @@
     public void testConstruct_tooSmallIdentifier() {
         assertThrows(IllegalArgumentException.class, () -> {
             final DeviceState state = new DeviceState(MINIMUM_DEVICE_STATE - 1 /* identifier */,
-                    null /* name */);
+                    null /* name */, 0 /* flags */);
         });
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
new file mode 100644
index 0000000..c9cf2f0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.devicestate;
+
+import static com.android.server.devicestate.OverrideRequestController.STATUS_ACTIVE;
+import static com.android.server.devicestate.OverrideRequestController.STATUS_CANCELED;
+import static com.android.server.devicestate.OverrideRequestController.STATUS_SUSPENDED;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import android.annotation.Nullable;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link OverrideRequestController}.
+ * <p/>
+ * Run with <code>atest OverrideRequestControllerTest</code>.
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public final class OverrideRequestControllerTest {
+    private TestStatusChangeListener mStatusListener;
+    private OverrideRequestController mController;
+
+    @Before
+    public void setup() {
+        mStatusListener = new TestStatusChangeListener();
+        mController = new OverrideRequestController(mStatusListener);
+    }
+
+    @Test
+    public void addRequest() {
+        OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        assertNull(mStatusListener.getLastStatus(request));
+
+        mController.addRequest(request);
+        assertEquals(mStatusListener.getLastStatus(request).intValue(), STATUS_ACTIVE);
+    }
+
+    @Test
+    public void addRequest_suspendExistingRequest() {
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        assertNull(mStatusListener.getLastStatus(firstRequest));
+
+        mController.addRequest(firstRequest);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
+
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        assertNull(mStatusListener.getLastStatus(secondRequest));
+
+        mController.addRequest(secondRequest);
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+    }
+
+    @Test
+    public void addRequest_cancelActiveRequest() {
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+
+        mController.addRequest(firstRequest);
+        mController.addRequest(secondRequest);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.cancelRequest(secondRequest.getToken());
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_CANCELED);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
+    }
+
+    @Test
+    public void addRequest_cancelSuspendedRequest() {
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+
+        mController.addRequest(firstRequest);
+        mController.addRequest(secondRequest);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.cancelRequest(firstRequest.getToken());
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_CANCELED);
+    }
+
+    @Test
+    public void handleBaseStateChanged() {
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */,
+                DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES /* flags */);
+
+        mController.addRequest(firstRequest);
+        mController.addRequest(secondRequest);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.handleBaseStateChanged();
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_CANCELED);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
+    }
+
+    @Test
+    public void handleProcessDied() {
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 1 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+
+        mController.addRequest(firstRequest);
+        mController.addRequest(secondRequest);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.handleProcessDied(1);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_CANCELED);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
+
+        mController.handleProcessDied(0);
+
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_CANCELED);
+    }
+
+    @Test
+    public void handleProcessDied_stickyRequests() {
+        mController.setStickyRequestsAllowed(true);
+
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 1 /* pid */,
+                0 /* requestedState */, 0 /* flags */);
+
+        mController.addRequest(firstRequest);
+        mController.addRequest(secondRequest);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.handleProcessDied(1);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.cancelStickyRequests();
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_CANCELED);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
+    }
+
+    @Test
+    public void handleNewSupportedStates() {
+        OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                1 /* requestedState */, 0 /* flags */);
+        OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */,
+                2 /* requestedState */, 0 /* flags */);
+
+        mController.addRequest(firstRequest);
+        mController.addRequest(secondRequest);
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_ACTIVE);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_SUSPENDED);
+
+        mController.handleNewSupportedStates(new int[]{ 0, 1 });
+
+        assertEquals(mStatusListener.getLastStatus(secondRequest).intValue(), STATUS_CANCELED);
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
+
+        mController.handleNewSupportedStates(new int[]{ 0 });
+
+        assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_CANCELED);
+    }
+
+    private static final class TestStatusChangeListener implements
+            OverrideRequestController.StatusChangeListener {
+        private Map<OverrideRequest, Integer> mLastStatusMap = new HashMap<>();
+
+        @Override
+        public void onStatusChanged(@NonNull OverrideRequest request, int newStatus) {
+            mLastStatusMap.put(request, newStatus);
+        }
+
+        @Nullable
+        public Integer getLastStatus(OverrideRequest request) {
+            return mLastStatusMap.get(request);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 5ba375b..fcfe273 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -67,6 +67,8 @@
 import com.android.server.sensors.SensorManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
+import com.google.common.collect.ImmutableMap;
+
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
@@ -82,6 +84,7 @@
 import java.time.Duration;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.LongStream;
@@ -223,7 +226,8 @@
                     break;
                 }
                 case DisplayViewport.VIEWPORT_EXTERNAL: {
-                    fail("EXTERNAL viewport should not exist.");
+                    // External view port is present for auto devices in the form of instrument
+                    // cluster.
                     break;
                 }
                 case DisplayViewport.VIEWPORT_VIRTUAL: {
@@ -259,9 +263,14 @@
         final int displayIds[] = bs.getDisplayIds();
         final int size = displayIds.length;
         assertTrue(size > 0);
+
+        Map<Integer, Integer> expectedDisplayTypeToViewPortTypeMapping = ImmutableMap.of(
+                Display.TYPE_INTERNAL, DisplayViewport.VIEWPORT_INTERNAL,
+                Display.TYPE_EXTERNAL, DisplayViewport.VIEWPORT_EXTERNAL
+        );
         for (int i = 0; i < size; i++) {
             DisplayInfo info = bs.getDisplayInfo(displayIds[i]);
-            assertEquals(info.type, Display.TYPE_INTERNAL);
+            assertTrue(expectedDisplayTypeToViewPortTypeMapping.keySet().contains(info.type));
         }
 
         displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -281,13 +290,13 @@
         // Now verify that each viewport's displayId is valid.
         Arrays.sort(displayIds);
         for (int i = 0; i < viewportSize; i++) {
-            DisplayViewport internalViewport = viewports.get(i);
-
-            // INTERNAL is the only one actual display.
-            assertNotNull(internalViewport);
-            assertEquals(DisplayViewport.VIEWPORT_INTERNAL, internalViewport.type);
-            assertTrue(internalViewport.valid);
-            assertTrue(Arrays.binarySearch(displayIds, internalViewport.displayId) >= 0);
+            DisplayViewport viewport = viewports.get(i);
+            assertNotNull(viewport);
+            DisplayInfo displayInfo = bs.getDisplayInfo(viewport.displayId);
+            assertTrue(expectedDisplayTypeToViewPortTypeMapping.get(displayInfo.type)
+                    == viewport.type);
+            assertTrue(viewport.valid);
+            assertTrue(Arrays.binarySearch(displayIds, viewport.displayId) >= 0);
         }
     }
 
@@ -885,6 +894,61 @@
         assertFalse(callback.mDisplayAddedCalled);
     }
 
+
+
+    @Test
+    public void testSettingTwoBrightnessConfigurationsOnMultiDisplay() {
+        Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+
+        // get the first two internal displays
+        Display[] displays = displayManager.getDisplays();
+        Display internalDisplayOne = null;
+        Display internalDisplayTwo = null;
+        for (Display display : displays) {
+            if (display.getType() == Display.TYPE_INTERNAL) {
+                if (internalDisplayOne == null) {
+                    internalDisplayOne = display;
+                } else {
+                    internalDisplayTwo = display;
+                    break;
+                }
+            }
+        }
+
+        // return if there are fewer than 2 displays on this device
+        if (internalDisplayOne == null || internalDisplayTwo == null) {
+            return;
+        }
+
+        final String uniqueDisplayIdOne = internalDisplayOne.getUniqueId();
+        final String uniqueDisplayIdTwo = internalDisplayTwo.getUniqueId();
+
+        BrightnessConfiguration configOne =
+                new BrightnessConfiguration.Builder(
+                        new float[]{0.0f, 12345.0f}, new float[]{15.0f, 400.0f})
+                        .setDescription("model:1").build();
+        BrightnessConfiguration configTwo =
+                new BrightnessConfiguration.Builder(
+                        new float[]{0.0f, 6789.0f}, new float[]{12.0f, 300.0f})
+                        .setDescription("model:2").build();
+
+        displayManager.setBrightnessConfigurationForDisplay(configOne,
+                uniqueDisplayIdOne);
+        displayManager.setBrightnessConfigurationForDisplay(configTwo,
+                uniqueDisplayIdTwo);
+
+        BrightnessConfiguration configFromOne =
+                displayManager.getBrightnessConfigurationForDisplay(uniqueDisplayIdOne);
+        BrightnessConfiguration configFromTwo =
+                displayManager.getBrightnessConfigurationForDisplay(uniqueDisplayIdTwo);
+
+        assertNotNull(configFromOne);
+        assertEquals(configOne, configFromOne);
+        assertEquals(configTwo, configFromTwo);
+
+    }
+
     private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)
             throws Exception {
         DisplayManagerService displayManager =
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..4564296 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -56,7 +56,11 @@
 import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
 import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
 import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Temperature;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
@@ -116,6 +120,8 @@
     public SensorManagerInternal mSensorManagerInternalMock;
     @Mock
     public DisplayManagerInternal mDisplayManagerInternalMock;
+    @Mock
+    public IThermalService mThermalServiceMock;
 
     @Before
     public void setUp() throws Exception {
@@ -124,6 +130,7 @@
         final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
         when(mContext.getContentResolver()).thenReturn(resolver);
         mInjector = spy(new FakesInjector());
+        when(mInjector.getThermalService()).thenReturn(mThermalServiceMock);
         mHandler = new Handler(Looper.getMainLooper());
 
         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1340,11 +1347,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 +1368,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);
     }
@@ -1514,12 +1554,52 @@
         assertNull(vote);
     }
 
+    @Test
+    public void testSkinTemperature() throws RemoteException {
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+        director.start(createMockSensorManager());
+
+        ArgumentCaptor<IThermalEventListener> thermalEventListener =
+                ArgumentCaptor.forClass(IThermalEventListener.class);
+
+        verify(mThermalServiceMock).registerThermalEventListenerWithType(
+            thermalEventListener.capture(), eq(Temperature.TYPE_SKIN));
+        final IThermalEventListener listener = thermalEventListener.getValue();
+
+        // Verify that there is no skin temperature vote initially.
+        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+        assertNull(vote);
+
+        // Set the skin temperature to critical and verify that we added a vote.
+        listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+        assertVoteForRefreshRateRange(vote, 0f, 60.f);
+
+        // Set the skin temperature to severe and verify that the vote is gone.
+        listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+        assertNull(vote);
+    }
+
+    private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
+        return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
+    }
+
     private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
         assertThat(vote).isNotNull();
         final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
         assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
     }
 
+    private void assertVoteForRefreshRateRange(
+            Vote vote, float refreshRateLow, float refreshRateHigh) {
+        assertThat(vote).isNotNull();
+        final RefreshRateRange expectedRange =
+                new RefreshRateRange(refreshRateLow, refreshRateHigh);
+        assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
+    }
+
     public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
         @Override
         public String getProperty(String namespace, String name) {
@@ -1710,6 +1790,16 @@
             return null;
         }
 
+        @Override
+        public boolean isDozeState(Display d) {
+            return false;
+        }
+
+        @Override
+        public IThermalService getThermalService() {
+            return null;
+        }
+
         void notifyPeakRefreshRateChanged() {
             if (mPeakRefreshRateObserver != null) {
                 mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
index 196454b..57a9cb2 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -17,13 +17,16 @@
 package com.android.server.display;
 
 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;
 
+import android.content.Context;
 import android.hardware.display.BrightnessConfiguration;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -144,15 +147,93 @@
     }
 
     @Test
-    public void testStoreAndReloadOfBrightnessConfigurations() {
+    public void testStoreAndReloadOfDisplayBrightnessConfigurations() {
+        final String uniqueDisplayId = "test:123";
+        int userSerial = 0;
+        String packageName = "pdsTestPackage";
         final float[] lux = { 0f, 10f };
         final float[] nits = {1f, 100f };
         final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
                 .setDescription("a description")
                 .build();
         mDataStore.loadIfNeeded();
+        assertNull(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
+                userSerial));
+
+        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+            @Override
+            public boolean hasStableUniqueId() {
+                return true;
+            }
+
+            @Override
+            public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+                return null;
+            }
+        };
+
+        mDataStore.setBrightnessConfigurationForDisplayLocked(config, testDisplayDevice, userSerial,
+                packageName);
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        mInjector.setWriteStream(baos);
+        mDataStore.saveIfNeeded();
+        assertTrue(mInjector.wasWriteSuccessful());
+        TestInjector newInjector = new TestInjector();
+        PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        newInjector.setReadStream(bais);
+        newDataStore.loadIfNeeded();
+        assertNotNull(newDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
+                userSerial));
+        assertEquals(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
+                userSerial), newDataStore.getBrightnessConfigurationForDisplayLocked(
+                        uniqueDisplayId, userSerial));
+    }
+
+    @Test
+    public void testSetBrightnessConfigurationFailsWithUnstableId() {
+        final String uniqueDisplayId = "test:123";
+        int userSerial = 0;
+        String packageName = "pdsTestPackage";
+        final float[] lux = { 0f, 10f };
+        final float[] nits = {1f, 100f };
+        final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
+                .setDescription("a description")
+                .build();
+        mDataStore.loadIfNeeded();
+        assertNull(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
+                userSerial));
+
+        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+            @Override
+            public boolean hasStableUniqueId() {
+                return false;
+            }
+
+            @Override
+            public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+                return null;
+            }
+        };
+
+        assertFalse(mDataStore.setBrightnessConfigurationForDisplayLocked(
+                config, testDisplayDevice, userSerial, packageName));
+    }
+
+    @Test
+    public void testStoreAndReloadOfBrightnessConfigurations() {
+        final float[] lux = { 0f, 10f };
+        final float[] nits = {1f, 100f };
+        final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
+                .setDescription("a description")
+                .build();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        String packageName = context.getPackageName();
+
+        mDataStore.loadIfNeeded();
         assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
-        mDataStore.setBrightnessConfigurationForUser(config, 0, "packagename");
+        mDataStore.setBrightnessConfigurationForUser(config, 0, packageName);
 
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         mInjector.setWriteStream(baos);
@@ -173,17 +254,18 @@
     public void testNullBrightnessConfiguration() {
         final float[] lux = { 0f, 10f };
         final float[] nits = {1f, 100f };
+        int userSerial = 0;
         final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
                 .setDescription("a description")
                 .build();
         mDataStore.loadIfNeeded();
-        assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+        assertNull(mDataStore.getBrightnessConfiguration(userSerial));
 
-        mDataStore.setBrightnessConfigurationForUser(config, 0, "packagename");
-        assertNotNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+        mDataStore.setBrightnessConfigurationForUser(config, userSerial, "packagename");
+        assertNotNull(mDataStore.getBrightnessConfiguration(userSerial));
 
-        mDataStore.setBrightnessConfigurationForUser(null, 0, "packagename");
-        assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
+        mDataStore.setBrightnessConfigurationForUser(null, userSerial, "packagename");
+        assertNull(mDataStore.getBrightnessConfiguration(userSerial));
     }
 
     public class TestInjector extends PersistentDataStore.Injector {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 88f70af..ac2756b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -22,16 +22,11 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.media.AudioManager;
-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;
@@ -41,8 +36,6 @@
 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.Collections;
@@ -55,28 +48,16 @@
     private Context mContextSpy;
     private HdmiControlService mHdmiControlService;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
 
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private int mPhysicalAddress;
 
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
             AudioManager getAudioManager() {
@@ -90,21 +71,11 @@
             }
 
             @Override
-            void wakeUp() {
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
 
             @Override
-            protected PowerManager getPowerManager() {
-                return new PowerManager(mContextSpy, mIPowerManagerMock,
-                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-            }
-
-            @Override
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
@@ -120,6 +91,8 @@
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mPhysicalAddress = 0x2000;
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
         mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 5cf81ec..4ff7c669 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -20,17 +20,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
-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 android.platform.test.annotations.Presubmit;
 
@@ -56,14 +51,14 @@
     private Context mContextSpy;
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private ArcInitiationActionFromAvr mAction;
 
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
 
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
-    @Mock private AudioManager mAudioManager;
+    @Mock
+    private AudioManager mAudioManager;
 
     @Before
     public void setUp() throws Exception {
@@ -71,14 +66,6 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy, Collections.emptyList()) {
                     @Override
@@ -87,16 +74,6 @@
                     }
 
                     @Override
-                    void wakeUp() {
-                    }
-
-                    @Override
-                    protected PowerManager getPowerManager() {
-                        return new PowerManager(mContextSpy, mIPowerManagerMock,
-                                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-                    }
-
-                    @Override
                     AudioManager getAudioManager() {
                         return mAudioManager;
                     }
@@ -133,6 +110,8 @@
         hdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(hdmiControlService));
         hdmiControlService.setMessageValidator(new HdmiCecMessageValidator(hdmiControlService));
         hdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        hdmiControlService.setPowerManager(mPowerManager);
         mAction = new ArcInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
 
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 1462839..c6bb914 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -20,17 +20,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
-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 android.platform.test.annotations.Presubmit;
 
@@ -55,16 +50,15 @@
 
     private Context mContextSpy;
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+    private FakePowerManagerWrapper mPowerManager;
     private ArcTerminationActionFromAvr mAction;
 
     private FakeNativeWrapper mNativeWrapper;
 
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
-
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
-    @Mock private AudioManager mAudioManager;
+    @Mock
+    private AudioManager mAudioManager;
 
     @Before
     public void setUp() throws Exception {
@@ -72,27 +66,9 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy, Collections.emptyList()) {
                     @Override
-                    void wakeUp() {
-                    }
-
-                    @Override
-                    protected PowerManager getPowerManager() {
-                        return new PowerManager(mContextSpy, mIPowerManagerMock,
-                                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-                    }
-
-                    @Override
                     AudioManager getAudioManager() {
                         return mAudioManager;
                     }
@@ -127,7 +103,8 @@
         hdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(hdmiControlService));
         hdmiControlService.setMessageValidator(new HdmiCecMessageValidator(hdmiControlService));
         hdmiControlService.initService();
-
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        hdmiControlService.setPowerManager(mPowerManager);
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
             @Override
             protected void setPreferredAddress(int addr) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index 57756f9..29eb0da 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -24,7 +24,6 @@
 
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -33,11 +32,7 @@
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
-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;
@@ -64,6 +59,7 @@
     private HdmiControlService mHdmiControlService;
     private HdmiCecLocalDevice mPlaybackDevice;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
 
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
@@ -71,9 +67,8 @@
 
     private DevicePowerStatusAction mDevicePowerStatusAction;
 
-    @Mock private IHdmiControlCallback mCallbackMock;
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
+    @Mock
+    private IHdmiControlCallback mCallbackMock;
 
     @Before
     public void setUp() throws Exception {
@@ -81,14 +76,6 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
             AudioManager getAudioManager() {
@@ -102,21 +89,11 @@
             }
 
             @Override
-            void wakeUp() {
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
 
             @Override
-            protected PowerManager getPowerManager() {
-                return new PowerManager(mContextSpy, mIPowerManagerMock,
-                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-            }
-
-            @Override
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
@@ -132,6 +109,8 @@
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mPhysicalAddress = 0x2000;
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
         mPlaybackDevice = new HdmiCecLocalDevicePlayback(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
new file mode 100644
index 0000000..f3070b6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.hardware.hdmi.HdmiControlManager.POWER_STATUS_ON;
+import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_STANDBY;
+import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
+
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_3;
+import static com.android.server.hdmi.DeviceSelectActionFromPlayback.STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE;
+import static com.android.server.hdmi.DeviceSelectActionFromPlayback.STATE_WAIT_FOR_DEVICE_POWER_ON;
+import static com.android.server.hdmi.DeviceSelectActionFromPlayback.STATE_WAIT_FOR_REPORT_POWER_STATUS;
+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.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.HdmiCecFeatureAction.ActionTimer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class DeviceSelectActionFromPlaybackTest {
+
+    private static final int PORT_1 = 1;
+    private static final int PORT_2 = 1;
+    private static final int PORT_3 = 1;
+    private static final int PHYSICAL_ADDRESS_PLAYBACK_1 = 0x1000;
+    private static final int PHYSICAL_ADDRESS_PLAYBACK_2 = 0x2000;
+    private static final int PHYSICAL_ADDRESS_PLAYBACK_3 = 0x3000;
+
+    private static final byte[] POWER_ON = new byte[] { POWER_STATUS_ON };
+    private static final byte[] POWER_STANDBY = new byte[] { POWER_STATUS_STANDBY };
+    private static final byte[] POWER_TRANSIENT_TO_ON = new byte[] { POWER_STATUS_TRANSIENT_TO_ON };
+    private static final HdmiCecMessage REPORT_POWER_STATUS_ON = new HdmiCecMessage(
+            ADDR_PLAYBACK_2, ADDR_PLAYBACK_1, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+    private static final HdmiCecMessage REPORT_POWER_STATUS_STANDBY = new HdmiCecMessage(
+            ADDR_PLAYBACK_2, ADDR_PLAYBACK_1, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_STANDBY);
+    private static final HdmiCecMessage REPORT_POWER_STATUS_TRANSIENT_TO_ON = new HdmiCecMessage(
+            ADDR_PLAYBACK_2, ADDR_PLAYBACK_1, Constants.MESSAGE_REPORT_POWER_STATUS,
+            POWER_TRANSIENT_TO_ON);
+    private static final HdmiCecMessage SET_STREAM_PATH = HdmiCecMessageBuilder.buildSetStreamPath(
+            ADDR_PLAYBACK_1, PHYSICAL_ADDRESS_PLAYBACK_2);
+    private static final HdmiCecMessage ROUTING_CHANGE = HdmiCecMessageBuilder.buildRoutingChange(
+            ADDR_PLAYBACK_1, PHYSICAL_ADDRESS_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_2);
+    private static final HdmiCecMessage ACTIVE_SOURCE = HdmiCecMessageBuilder.buildActiveSource(
+            ADDR_PLAYBACK_2, PHYSICAL_ADDRESS_PLAYBACK_2);
+    private static final HdmiDeviceInfo INFO_PLAYBACK_1 = new HdmiDeviceInfo(
+            ADDR_PLAYBACK_1, PHYSICAL_ADDRESS_PLAYBACK_1, PORT_1, HdmiDeviceInfo.DEVICE_PLAYBACK,
+            0x1234, "Playback 1",
+            HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
+    private static final HdmiDeviceInfo INFO_PLAYBACK_2 = new HdmiDeviceInfo(
+            ADDR_PLAYBACK_2, PHYSICAL_ADDRESS_PLAYBACK_2, PORT_2, HdmiDeviceInfo.DEVICE_PLAYBACK,
+            0x1234, "Playback 2",
+            HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
+    private static final HdmiDeviceInfo INFO_PLAYBACK_3 = new HdmiDeviceInfo(
+            ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3, PORT_3, HdmiDeviceInfo.DEVICE_PLAYBACK,
+            0x1234, "Playback 3",
+            HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
+
+    private HdmiCecController mHdmiCecController;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
+    private HdmiCecNetwork mHdmiCecNetwork;
+    private HdmiControlService mHdmiControlService;
+    private HdmiMhlControllerStub mHdmiMhlControllerStub;
+
+    private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
+    private Looper mMyLooper;
+    private TestLooper mTestLooper = new TestLooper();
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+
+    @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
+                    protected void writeStringSystemProperty(String key, String value) {
+                        // do nothing
+                    }
+
+                    @Override
+                    boolean isPowerStandbyOrTransient() {
+                        return false;
+                    }
+                };
+
+
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
+        mHdmiCecLocalDevicePlayback.init();
+        mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+                mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiMhlControllerStub = HdmiMhlControllerStub.create(mHdmiControlService);
+        mHdmiControlService.setHdmiMhlController(mHdmiMhlControllerStub);
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(mHdmiMhlControllerStub);
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mHdmiCecNetwork = new HdmiCecNetwork(mHdmiControlService,
+                mHdmiCecController, mHdmiMhlControllerStub);
+        mHdmiControlService.setHdmiCecNetwork(mHdmiCecNetwork);
+
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+        mHdmiControlService.initService();
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mNativeWrapper.setPhysicalAddress(0x0000);
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
+        mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
+
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_PLAYBACK_1);
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_PLAYBACK_2);
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_PLAYBACK_3);
+    }
+
+    private static class TestActionTimer implements ActionTimer {
+        private int mState;
+
+        @Override
+        public void sendTimerMessage(int state, long delayMillis) {
+            mState = state;
+        }
+
+        @Override
+        public void clearTimerMessage() {
+        }
+
+        private int getState() {
+            return mState;
+        }
+    }
+
+    private static class TestCallback extends IHdmiControlCallback.Stub {
+        private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>();
+
+        @Override
+        public void onComplete(int result) {
+            mCallbackResult.add(result);
+        }
+
+        private int getResult() {
+            assertThat(mCallbackResult.size()).isEqualTo(1);
+            return mCallbackResult.get(0);
+        }
+    }
+
+    private DeviceSelectActionFromPlayback createDeviceSelectActionFromPlayback(
+            TestActionTimer actionTimer,
+            TestCallback callback,
+            boolean isCec20) {
+        HdmiDeviceInfo hdmiDeviceInfo =
+                mHdmiControlService.getHdmiCecNetwork().getCecDeviceInfo(ADDR_PLAYBACK_2);
+        DeviceSelectActionFromPlayback action = new DeviceSelectActionFromPlayback(
+                mHdmiCecLocalDevicePlayback,
+                hdmiDeviceInfo, callback, isCec20);
+        action.setActionTimer(actionTimer);
+        return action;
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInPowerOnStatus_Cec14b() {
+        // TV was watching playback3 device connected at port 3, and wants to select
+        // playback2.
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/false);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_ON);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInStandbyStatus_Cec14b() {
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/false);
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_STANDBY);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.processCommand(REPORT_POWER_STATUS_ON);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInStandbyStatusWithSomeTimeouts_Cec14b() {
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/false);
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_STANDBY);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_TRANSIENT_TO_ON);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_ON);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInStandbyAfterTimeoutForReportPowerStatus_Cec14b() {
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/false);
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_STANDBY);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_TRANSIENT_TO_ON);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.handleTimerEvent(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        // Give up getting power status, and just send <Routing Change>
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_ReachSetStreamPath_Cec14b() {
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/false);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_ON);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(
+                STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE);
+        action.handleTimerEvent(STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_ReachSetStreamPathDeviceInPowerOnStatus_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_PLAYBACK_2,
+                HdmiControlManager.POWER_STATUS_ON);
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/true);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(
+                STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE);
+        action.handleTimerEvent(STATE_WAIT_FOR_ACTIVE_SOURCE_MESSAGE_AFTER_ROUTING_CHANGE);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(SET_STREAM_PATH);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInPowerOnStatus_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_PLAYBACK_2,
+                HdmiControlManager.POWER_STATUS_ON);
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/true);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInPowerUnknownStatus_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_PLAYBACK_2,
+                HdmiControlManager.POWER_STATUS_UNKNOWN);
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/true);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_ON);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testDeviceSelect_DeviceInStandbyStatus_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_PLAYBACK_2,
+                HdmiControlManager.POWER_STATUS_STANDBY);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_3, PHYSICAL_ADDRESS_PLAYBACK_3,
+                "testDeviceSelectFromPlayback");
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        DeviceSelectActionFromPlayback action = createDeviceSelectActionFromPlayback(actionTimer,
+                callback, /*isCec20=*/true);
+        action.start();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_REPORT_POWER_STATUS);
+        action.processCommand(REPORT_POWER_STATUS_STANDBY);
+        mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.handleTimerEvent(STATE_WAIT_FOR_DEVICE_POWER_ON);
+        action.processCommand(REPORT_POWER_STATUS_ON);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(ROUTING_CHANGE);
+        action.processCommand(ACTIVE_SOURCE);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
similarity index 90%
rename from services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
rename to services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
index 0d5d05c..28ee592 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
@@ -23,8 +23,8 @@
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
 import static com.android.server.hdmi.Constants.ADDR_TV;
-import static com.android.server.hdmi.DeviceSelectAction.STATE_WAIT_FOR_DEVICE_POWER_ON;
-import static com.android.server.hdmi.DeviceSelectAction.STATE_WAIT_FOR_REPORT_POWER_STATUS;
+import static com.android.server.hdmi.DeviceSelectActionFromTv.STATE_WAIT_FOR_DEVICE_POWER_ON;
+import static com.android.server.hdmi.DeviceSelectActionFromTv.STATE_WAIT_FOR_REPORT_POWER_STATUS;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -34,11 +34,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
-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;
@@ -50,15 +46,13 @@
 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.Collections;
 
 @SmallTest
 @RunWith(JUnit4.class)
-public class DeviceSelectActionTest {
+public class DeviceSelectActionFromTvTest {
 
     private static final int PORT_1 = 1;
     private static final int PORT_2 = 1;
@@ -89,19 +83,13 @@
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
 
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
 
@@ -114,10 +102,6 @@
                     }
 
                     @Override
-                    void wakeUp() {
-                    }
-
-                    @Override
                     protected void writeStringSystemProperty(String key, String value) {
                         // do nothing
                     }
@@ -126,12 +110,6 @@
                     boolean isPowerStandbyOrTransient() {
                         return false;
                     }
-
-                    @Override
-                    protected PowerManager getPowerManager() {
-                        return new PowerManager(context, mIPowerManagerMock,
-                                mIThermalServiceMock, new Handler(mMyLooper));
-                    }
                 };
 
         mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
@@ -154,6 +132,8 @@
                                  true, false, false);
         mNativeWrapper.setPortInfo(hdmiPortInfos);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mNativeWrapper.setPhysicalAddress(0x0000);
         mTestLooper.dispatchAll();
@@ -193,12 +173,12 @@
         }
     }
 
-    private DeviceSelectAction createDeviceSelectAction(TestActionTimer actionTimer,
+    private DeviceSelectActionFromTv createDeviceSelectAction(TestActionTimer actionTimer,
                                                         TestCallback callback,
                                                         boolean isCec20) {
         HdmiDeviceInfo hdmiDeviceInfo =
                 mHdmiControlService.getHdmiCecNetwork().getCecDeviceInfo(ADDR_PLAYBACK_1);
-        DeviceSelectAction action = new DeviceSelectAction(mHdmiCecLocalDeviceTv,
+        DeviceSelectActionFromTv action = new DeviceSelectActionFromTv(mHdmiCecLocalDeviceTv,
                                                            hdmiDeviceInfo, callback, isCec20);
         action.setActionTimer(actionTimer);
         return action;
@@ -210,7 +190,7 @@
         // playback1.
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/false);
         mHdmiCecLocalDeviceTv.updateActiveSource(ADDR_PLAYBACK_2, PHYSICAL_ADDRESS_PLAYBACK_2,
                                                  "testDeviceSelect");
@@ -231,7 +211,7 @@
                                                  "testDeviceSelect");
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/false);
         action.start();
         mTestLooper.dispatchAll();
@@ -257,7 +237,7 @@
                                                  "testDeviceSelect");
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/false);
         action.start();
         mTestLooper.dispatchAll();
@@ -284,7 +264,7 @@
                                                  "testDeviceSelect");
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/false);
         action.start();
         mTestLooper.dispatchAll();
@@ -312,7 +292,7 @@
                 HdmiControlManager.POWER_STATUS_ON);
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/true);
         mHdmiCecLocalDeviceTv.updateActiveSource(ADDR_PLAYBACK_2, PHYSICAL_ADDRESS_PLAYBACK_2,
                                                  "testDeviceSelect");
@@ -328,7 +308,7 @@
                 HdmiControlManager.POWER_STATUS_UNKNOWN);
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/true);
         mHdmiCecLocalDeviceTv.updateActiveSource(ADDR_PLAYBACK_2, PHYSICAL_ADDRESS_PLAYBACK_2,
                                                  "testDeviceSelect");
@@ -351,7 +331,7 @@
                                                  "testDeviceSelect");
         TestActionTimer actionTimer = new TestActionTimer();
         TestCallback callback = new TestCallback();
-        DeviceSelectAction action = createDeviceSelectAction(actionTimer, callback,
+        DeviceSelectActionFromTv action = createDeviceSelectAction(actionTimer, callback,
                                         /*isCec20=*/true);
         action.start();
         mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
new file mode 100644
index 0000000..7c8a11e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
@@ -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.hdmi;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/**
+ * Fake class which stubs PowerManagerWrapper (useful for testing).
+ */
+final class FakePowerManagerWrapper extends PowerManagerWrapper {
+    private boolean mInteractive;
+
+    FakePowerManagerWrapper(@NonNull Context context) {
+        super(context);
+        mInteractive = true;
+    }
+
+    @Override
+    boolean isInteractive() {
+        return mInteractive;
+    }
+
+    void setInteractive(boolean interactive) {
+        mInteractive = interactive;
+    }
+
+    @Override
+    void wakeUp(long time, int reason, String details) {
+        mInteractive = true;
+        return;
+    }
+
+    @Override
+    void goToSleep(long time, int reason, int flags) {
+        mInteractive = false;
+        return;
+    }
+
+    // Don't stub WakeLock.
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index da10ec4..f30e97a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -31,7 +31,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -39,15 +38,11 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Binder;
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.IThermalService;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
-import android.stats.hdmi.nano.HdmiStatsEnums;
+import android.stats.hdmi.HdmiStatsEnums;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -58,8 +53,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -77,6 +71,7 @@
     private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
     private HdmiMhlControllerStub mHdmiMhlControllerStub;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private HdmiCecNetwork mHdmiCecNetwork;
     private Looper mLooper;
     private Context mContextSpy;
@@ -85,13 +80,8 @@
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private HdmiPortInfo[] mHdmiPortInfo;
 
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() throws RemoteException {
-        MockitoAnnotations.initMocks(this);
-
         mHdmiCecAtomWriterSpy = spy(new HdmiCecAtomWriter());
 
         mLooper = mTestLooper.getLooper();
@@ -99,12 +89,6 @@
         mContextSpy = spy(new ContextWrapper(
                 InstrumentationRegistry.getInstrumentation().getTargetContext()));
 
-
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                        mIThermalServiceMock, new Handler(mLooper)));
-        doReturn(true).when(mIPowerManagerMock).isInteractive();
-
         mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.emptyList()));
         doNothing().when(mHdmiControlServiceSpy)
                 .writeStringSystemProperty(anyString(), anyString());
@@ -145,10 +129,14 @@
         mLocalDevices.add(mHdmiCecLocalDevicePlayback);
 
         mHdmiControlServiceSpy.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlServiceSpy.setPowerManager(mPowerManager);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
         mTestLooper.dispatchAll();
+
+        Mockito.reset(mHdmiCecAtomWriterSpy);
     }
 
     @Test
@@ -164,6 +152,7 @@
                 mPhysicalAddress);
 
         mHdmiCecController.sendCommand(message);
+        mTestLooper.dispatchAll();
 
         verify(mHdmiCecAtomWriterSpy, times(1)).messageReported(
                 eq(message),
@@ -208,4 +197,109 @@
                 eq(callerUid),
                 anyInt());
     }
+
+    @Test
+    public void testMessageReported_writesAtom_userControlPressed() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildUserControlPressed(
+                Constants.ADDR_TV,
+                Constants.ADDR_PLAYBACK_1,
+                HdmiCecKeycode.CEC_KEYCODE_MUTE
+        );
+
+        mHdmiCecAtomWriterSpy.messageReported(
+                message,
+                HdmiStatsEnums.INCOMING,
+                1234);
+
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .writeHdmiCecMessageReportedAtom(
+                        1234,
+                        HdmiStatsEnums.INCOMING,
+                        Constants.ADDR_TV,
+                        Constants.ADDR_PLAYBACK_1,
+                        Constants.MESSAGE_USER_CONTROL_PRESSED,
+                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
+                        HdmiStatsEnums.VOLUME_MUTE,
+                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
+    }
+
+    @Test
+    public void testMessageReported_writesAtom_userControlPressed_noParams() {
+        HdmiCecMessage message = new HdmiCecMessage(
+                Constants.ADDR_TV,
+                Constants.ADDR_PLAYBACK_1,
+                Constants.MESSAGE_USER_CONTROL_PRESSED,
+                new byte[0]);
+
+        mHdmiCecAtomWriterSpy.messageReported(
+                message,
+                HdmiStatsEnums.INCOMING,
+                1234);
+
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .writeHdmiCecMessageReportedAtom(
+                        1234,
+                        HdmiStatsEnums.INCOMING,
+                        Constants.ADDR_TV,
+                        Constants.ADDR_PLAYBACK_1,
+                        Constants.MESSAGE_USER_CONTROL_PRESSED,
+                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
+                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
+                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
+    }
+
+    @Test
+    public void testMessageReported_writesAtom_featureAbort() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                Constants.ADDR_TV,
+                Constants.ADDR_PLAYBACK_1,
+                Constants.MESSAGE_RECORD_ON,
+                Constants.ABORT_UNRECOGNIZED_OPCODE
+        );
+
+        mHdmiCecAtomWriterSpy.messageReported(
+                message,
+                HdmiStatsEnums.INCOMING,
+                1234);
+
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .writeHdmiCecMessageReportedAtom(
+                        1234,
+                        HdmiStatsEnums.INCOMING,
+                        Constants.ADDR_TV,
+                        Constants.ADDR_PLAYBACK_1,
+                        Constants.MESSAGE_FEATURE_ABORT,
+                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
+                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
+                        Constants.MESSAGE_RECORD_ON,
+                        HdmiStatsEnums.UNRECOGNIZED_OPCODE);
+    }
+
+    @Test
+    public void testMessageReported_writesAtom_featureAbort_noParams() {
+        HdmiCecMessage message = new HdmiCecMessage(
+                Constants.ADDR_TV,
+                Constants.ADDR_PLAYBACK_1,
+                Constants.MESSAGE_FEATURE_ABORT,
+                new byte[0]);
+
+        mHdmiCecAtomWriterSpy.messageReported(
+                message,
+                HdmiStatsEnums.INCOMING,
+                1234);
+
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .writeHdmiCecMessageReportedAtom(
+                        1234,
+                        HdmiStatsEnums.INCOMING,
+                        Constants.ADDR_TV,
+                        Constants.ADDR_PLAYBACK_1,
+                        Constants.MESSAGE_FEATURE_ABORT,
+                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
+                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
+                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
+                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 7eb8990..17f827d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -31,11 +31,7 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.media.AudioManager;
-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 android.platform.test.annotations.Presubmit;
 
@@ -49,8 +45,6 @@
 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.Collections;
@@ -70,6 +64,7 @@
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
     private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
@@ -84,15 +79,9 @@
     private HdmiDeviceInfo mDeviceInfo;
     private boolean mArcSupport;
     private HdmiPortInfo[] mHdmiPortInfo;
-    private boolean mWokenUp;
-
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
 
@@ -156,11 +145,6 @@
                 }
 
                 @Override
-                void wakeUp() {
-                    mWokenUp = true;
-                }
-
-                @Override
                 void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
                     mDeviceInfo = device;
                     mInvokeDeviceEventState = status;
@@ -180,12 +164,6 @@
                             return defVal;
                     }
                 }
-
-                @Override
-                protected PowerManager getPowerManager() {
-                    return new PowerManager(context, mIPowerManagerMock,
-                            mIThermalServiceMock, new Handler(mMyLooper));
-                }
             };
 
         mHdmiControlService.getHdmiCecConfig().setIntValue(
@@ -228,6 +206,8 @@
                 4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS, true, false, false);
         mNativeWrapper.setPortInfo(mHdmiPortInfo);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
         // No TV device interacts with AVR so system audio control won't be turned on here
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
@@ -675,16 +655,16 @@
 
     @Test
     public void doNotWakeUpOnHotPlug_PlugIn() {
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         mHdmiCecLocalDeviceAudioSystem.onHotplug(0, true);
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
     public void doNotWakeUpOnHotPlug_PlugOut() {
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         mHdmiCecLocalDeviceAudioSystem.onHotplug(0, false);
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 337276d..8a84c6f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -24,18 +24,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.when;
-
 import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.IThermalService;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
@@ -49,8 +43,6 @@
 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.Collections;
@@ -75,22 +67,15 @@
     private FakeNativeWrapper mNativeWrapper;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
+    private FakePowerManagerWrapper mPowerManager;
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private int mPlaybackPhysicalAddress;
     private int mPlaybackLogicalAddress;
     private boolean mWokenUp;
-    private boolean mStandby;
     private boolean mActiveMediaSessionsPaused;
 
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
 
@@ -100,12 +85,7 @@
                     @Override
                     void wakeUp() {
                         mWokenUp = true;
-                    }
-
-                    @Override
-                    void standby() {
-                        mStandby = true;
-                        mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
+                        super.wakeUp();
                     }
 
                     @Override
@@ -114,11 +94,6 @@
                     }
 
                     @Override
-                    protected boolean isStandbyMessageReceived() {
-                        return mStandby;
-                    }
-
-                    @Override
                     boolean isControlEnabled() {
                         return true;
                     }
@@ -144,9 +119,8 @@
                     }
 
                     @Override
-                    protected PowerManager getPowerManager() {
-                        return new PowerManager(context, mIPowerManagerMock,
-                                mIThermalServiceMock, new Handler(mMyLooper));
+                    boolean canGoToStandby() {
+                        return true;
                     }
                 };
 
@@ -167,6 +141,8 @@
         mNativeWrapper.setPortInfo(hdmiPortInfos);
         mNativeWrapper.setPortConnectionStatus(1, true);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mPlaybackPhysicalAddress = 0x2000;
         mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
@@ -183,7 +159,7 @@
         mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
                 HdmiProperties.playback_device_action_on_routing_control_values.NONE;
 
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
 
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
@@ -196,7 +172,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
         assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
     }
 
@@ -205,7 +181,7 @@
         mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
                 HdmiProperties.playback_device_action_on_routing_control_values.NONE;
 
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
 
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
@@ -218,7 +194,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
         assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
     }
 
@@ -227,7 +203,7 @@
         mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
                 HdmiProperties.playback_device_action_on_routing_control_values.WAKE_UP_ONLY;
 
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
 
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
@@ -240,7 +216,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
     }
 
@@ -249,7 +225,7 @@
         mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
                 HdmiProperties.playback_device_action_on_routing_control_values.WAKE_UP_ONLY;
 
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
 
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
@@ -262,7 +238,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
     }
 
@@ -273,7 +249,7 @@
                         .playback_device_action_on_routing_control_values
                         .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
 
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
 
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
@@ -286,7 +262,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
     }
 
@@ -297,7 +273,7 @@
                         .playback_device_action_on_routing_control_values
                         .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
 
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
 
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
@@ -310,7 +286,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
     }
 
@@ -321,7 +297,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
@@ -331,7 +307,7 @@
                 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 ADDR_INVALID);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -341,7 +317,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
                         mPlaybackPhysicalAddress);
@@ -352,7 +328,7 @@
                 mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 mPlaybackLogicalAddress);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -362,7 +338,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
                         mPlaybackPhysicalAddress);
@@ -373,7 +349,7 @@
                 mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 ADDR_INVALID);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -383,13 +359,13 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -399,13 +375,13 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -415,14 +391,14 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
                         mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -480,7 +456,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message = HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
@@ -489,7 +465,7 @@
                 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 ADDR_INVALID);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -499,7 +475,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
                         mPlaybackPhysicalAddress);
@@ -510,7 +486,7 @@
                 mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 mPlaybackLogicalAddress);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -520,7 +496,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
                         mPlaybackPhysicalAddress);
@@ -531,7 +507,7 @@
                 mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 ADDR_INVALID);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -541,13 +517,13 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -557,13 +533,13 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -573,14 +549,14 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
                         mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -681,16 +657,16 @@
 
     @Test
     public void doNotWakeUpOnHotPlug_PlugIn() {
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         mHdmiCecLocalDevicePlayback.onHotplug(0, true);
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
     public void doNotWakeUpOnHotPlug_PlugOut() {
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         mHdmiCecLocalDevicePlayback.onHotplug(0, false);
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -1048,13 +1024,13 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
                 mPlaybackPhysicalAddress);
@@ -1067,12 +1043,12 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
                 0x0000);
@@ -1085,13 +1061,13 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
     }
 
@@ -1100,12 +1076,12 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
     }
 
@@ -1164,7 +1140,7 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         // 1. DUT is <AS>.
         HdmiCecMessage message1 =
                 HdmiCecMessageBuilder.buildActiveSource(
@@ -1173,15 +1149,15 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message1))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         // 2. DUT loses <AS> and goes to sleep.
         HdmiCecMessage message2 = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message2))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
+        mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
         // 3. DUT becomes <AS> again.
-        mWokenUp = false;
         HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
                 mPlaybackPhysicalAddress);
         mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
@@ -1191,7 +1167,7 @@
                         mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
                         mPlaybackPhysicalAddress);
         assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         // 4. DUT turned off.
         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
@@ -1463,8 +1439,7 @@
 
     @Test
     public void handleSetStreamPath_Dreaming() throws RemoteException {
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
+        mPowerManager.setInteractive(true);
         mWokenUp = false;
 
         HdmiCecMessage message =
@@ -1474,6 +1449,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mWokenUp).isTrue();
     }
 
@@ -1484,7 +1460,7 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message))
@@ -1494,7 +1470,7 @@
                 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 ADDR_INVALID);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -1504,13 +1480,13 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -1520,13 +1496,13 @@
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message))
                 .isEqualTo(Constants.HANDLED);
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -1733,7 +1709,7 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 HdmiControlManager.POWER_CONTROL_MODE_TV);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         mHdmiControlService.toggleAndFollowTvPower();
         HdmiCecMessage tvPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV,
                 mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON);
@@ -1744,7 +1720,7 @@
         HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildStandby(
                 mPlaybackLogicalAddress, ADDR_TV);
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -1752,7 +1728,7 @@
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         mHdmiControlService.toggleAndFollowTvPower();
         HdmiCecMessage tvPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV,
                 mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON);
@@ -1763,12 +1739,12 @@
         HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildStandby(
                 mPlaybackLogicalAddress, ADDR_BROADCAST);
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
-        assertThat(mStandby).isTrue();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
     public void toggleAndFollowTvPower_TvStatusStandby() {
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         mHdmiControlService.toggleAndFollowTvPower();
         HdmiCecMessage tvPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV,
                 mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_STANDBY);
@@ -1782,12 +1758,12 @@
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
         assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
         assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
     public void toggleAndFollowTvPower_TvStatusUnknown() {
-        mStandby = false;
+        mPowerManager.setInteractive(true);
         mHdmiControlService.toggleAndFollowTvPower();
         HdmiCecMessage tvPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV,
                 mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_UNKNOWN);
@@ -1802,31 +1778,31 @@
                 mPlaybackLogicalAddress, Constants.ADDR_TV);
         assertThat(mNativeWrapper.getResultMessages()).contains(userControlPressed);
         assertThat(mNativeWrapper.getResultMessages()).contains(userControlReleased);
-        assertThat(mStandby).isFalse();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
     public void toggleAndFollowTvPower_isInteractive() throws RemoteException {
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+        mPowerManager.setInteractive(true);
         mActiveMediaSessionsPaused = false;
         mWokenUp = false;
 
         mHdmiControlService.toggleAndFollowTvPower();
 
         assertThat(mActiveMediaSessionsPaused).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mWokenUp).isFalse();
     }
 
     @Test
     public void toggleAndFollowTvPower_isNotInteractive() throws RemoteException {
-        when(mIPowerManagerMock.isInteractive()).thenReturn(false);
+        mPowerManager.setInteractive(false);
         mActiveMediaSessionsPaused = false;
-        mWokenUp = false;
 
         mHdmiControlService.toggleAndFollowTvPower();
 
         assertThat(mActiveMediaSessionsPaused).isFalse();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
 
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..7acf946 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;
@@ -38,11 +37,7 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
-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;
@@ -68,18 +63,15 @@
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private int mTvPhysicalAddress;
     private int mTvLogicalAddress;
-    private boolean mWokenUp;
 
     @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
-    @Mock private AudioManager mAudioManager;
+    private AudioManager mAudioManager;
 
     @Before
     public void setUp() {
@@ -92,11 +84,6 @@
                 new HdmiControlService(InstrumentationRegistry.getTargetContext(),
                         Collections.emptyList()) {
                     @Override
-                    void wakeUp() {
-                        mWokenUp = true;
-                    }
-
-                    @Override
                     boolean isControlEnabled() {
                         return true;
                     }
@@ -117,12 +104,6 @@
                     }
 
                     @Override
-                    protected PowerManager getPowerManager() {
-                        return new PowerManager(context, mIPowerManagerMock,
-                                mIThermalServiceMock, new Handler(mMyLooper));
-                    }
-
-                    @Override
                     AudioManager getAudioManager() {
                         return mAudioManager;
                     }
@@ -146,6 +127,8 @@
                 new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true);
         mNativeWrapper.setPortInfo(hdmiPortInfos);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTvPhysicalAddress = 0x0000;
         mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress);
@@ -239,12 +222,12 @@
                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
         mTestLooper.dispatchAll();
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
                 mTvLogicalAddress);
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -253,12 +236,12 @@
                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
         mTestLooper.dispatchAll();
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         HdmiCecMessage imageViewOn = new HdmiCecMessage(ADDR_PLAYBACK_1, mTvLogicalAddress,
                 Constants.MESSAGE_IMAGE_VIEW_ON, HdmiCecMessage.EMPTY_PARAM);
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(imageViewOn)).isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isTrue();
+        assertThat(mPowerManager.isInteractive()).isTrue();
     }
 
     @Test
@@ -267,12 +250,12 @@
                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED);
         mTestLooper.dispatchAll();
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
                 mTvLogicalAddress);
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -281,12 +264,12 @@
                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED);
         mTestLooper.dispatchAll();
-        mWokenUp = false;
+        mPowerManager.setInteractive(false);
         HdmiCecMessage imageViewOn = new HdmiCecMessage(ADDR_PLAYBACK_1, mTvLogicalAddress,
                 Constants.MESSAGE_IMAGE_VIEW_ON, HdmiCecMessage.EMPTY_PARAM);
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(imageViewOn)).isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
-        assertThat(mWokenUp).isFalse();
+        assertThat(mPowerManager.isInteractive()).isFalse();
     }
 
     @Test
@@ -539,69 +522,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/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
index e7d1b95..1048eb5 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
@@ -542,4 +542,13 @@
         assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress);
         assertThat(cecDeviceInfo.getCecVersion()).isEqualTo(cecVersion);
     }
+
+    @Test
+    public void getSafeCecDevicesLocked_addDevice_sizeOne() {
+        HdmiDeviceInfo cecDeviceInfo = new HdmiDeviceInfo();
+
+        mHdmiCecNetwork.addCecDevice(cecDeviceInfo);
+
+        assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index ceb41cf..bff1296 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -20,17 +20,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPortInfo;
-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 android.platform.test.annotations.Presubmit;
 
@@ -43,8 +38,6 @@
 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.Collections;
@@ -61,28 +54,16 @@
             HdmiControlManager.POWER_STATUS_STANDBY};
     private HdmiCecPowerStatusController mHdmiCecPowerStatusController;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
     private HdmiControlService mHdmiControlService;
     private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
         Context contextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         Looper myLooper = mTestLooper.getLooper();
-        when(contextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(contextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(myLooper)));
-        when(contextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(contextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(myLooper)));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(contextSpy, Collections.emptyList()) {
             @Override
@@ -125,6 +106,8 @@
         mNativeWrapper.setPortInfo(hdmiPortInfos);
         mNativeWrapper.setPortConnectionStatus(1, true);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(contextSpy);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mHdmiControlService.getHdmiCecNetwork().initPortInfo();
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mNativeWrapper.setPhysicalAddress(0x2000);
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 6492e0f..c525f9be 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -35,7 +35,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -44,10 +43,7 @@
 import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
 import android.hardware.hdmi.IHdmiControlStatusChangeListener;
 import android.os.Binder;
-import android.os.IPowerManager;
-import android.os.IThermalService;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
@@ -60,9 +56,7 @@
 import org.junit.Test;
 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;
 import java.util.Arrays;
@@ -77,107 +71,6 @@
 @RunWith(JUnit4.class)
 public class HdmiControlServiceTest {
 
-    protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
-
-        private boolean mCanGoToStandby;
-        private boolean mIsStandby;
-        private boolean mIsDisabled;
-
-        MockPlaybackDevice(HdmiControlService service) {
-            super(service);
-        }
-
-        @Override
-        protected void onAddressAllocated(int logicalAddress, int reason) {}
-
-        @Override
-        protected int getPreferredAddress() {
-            return 0;
-        }
-
-        @Override
-        protected void setPreferredAddress(int addr) {}
-
-        @Override
-        protected boolean canGoToStandby() {
-            return mCanGoToStandby;
-        }
-
-        @Override
-        protected void disableDevice(
-                boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
-            mIsDisabled = true;
-            originalCallback.onCleared(this);
-        }
-
-        @Override
-        protected void onStandby(boolean initiatedByCec, int standbyAction) {
-            mIsStandby = true;
-        }
-
-        protected boolean isStandby() {
-            return mIsStandby;
-        }
-
-        protected boolean isDisabled() {
-            return mIsDisabled;
-        }
-
-        protected void setCanGoToStandby(boolean canGoToStandby) {
-            mCanGoToStandby = canGoToStandby;
-        }
-    }
-    protected static class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem {
-
-        private boolean mCanGoToStandby;
-        private boolean mIsStandby;
-        private boolean mIsDisabled;
-
-        MockAudioSystemDevice(HdmiControlService service) {
-            super(service);
-        }
-
-        @Override
-        protected void onAddressAllocated(int logicalAddress, int reason) {}
-
-        @Override
-        protected int getPreferredAddress() {
-            return 0;
-        }
-
-        @Override
-        protected void setPreferredAddress(int addr) {}
-
-        @Override
-        protected boolean canGoToStandby() {
-            return mCanGoToStandby;
-        }
-
-        @Override
-        protected void disableDevice(
-                boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
-            mIsDisabled = true;
-            originalCallback.onCleared(this);
-        }
-
-        @Override
-        protected void onStandby(boolean initiatedByCec, int standbyAction) {
-            mIsStandby = true;
-        }
-
-        protected boolean isStandby() {
-            return mIsStandby;
-        }
-
-        protected boolean isDisabled() {
-            return mIsDisabled;
-        }
-
-        protected void setCanGoToStandby(boolean canGoToStandby) {
-            mCanGoToStandby = canGoToStandby;
-        }
-    }
-
     private static final String TAG = "HdmiControlServiceTest";
     private Context mContextSpy;
     private HdmiControlService mHdmiControlServiceSpy;
@@ -185,28 +78,16 @@
     private MockAudioSystemDevice mAudioSystemDeviceSpy;
     private MockPlaybackDevice mPlaybackDeviceSpy;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private HdmiPortInfo[] mHdmiPortInfo;
 
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, null));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, null));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
 
         mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.emptyList()));
@@ -237,15 +118,17 @@
         mLocalDevices.add(mPlaybackDeviceSpy);
         mHdmiPortInfo = new HdmiPortInfo[4];
         mHdmiPortInfo[0] =
-            new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
+                new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
         mHdmiPortInfo[1] =
-            new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false);
+                new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false);
         mHdmiPortInfo[2] =
-            new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false);
+                new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false);
         mHdmiPortInfo[3] =
-            new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
+                new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
         mNativeWrapper.setPortInfo(mHdmiPortInfo);
         mHdmiControlServiceSpy.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlServiceSpy.setPowerManager(mPowerManager);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
 
         mTestLooper.dispatchAll();
@@ -283,7 +166,7 @@
 
     @Test
     public void initialPowerStatus_quiescentBoot_isTransientToStandby() throws RemoteException {
-        when(mIPowerManagerMock.isInteractive()).thenReturn(false);
+        mPowerManager.setInteractive(false);
         assertThat(mHdmiControlServiceSpy.getInitialPowerStatus()).isEqualTo(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY);
     }
@@ -298,7 +181,7 @@
 
     @Test
     public void powerStatusAfterBootComplete_quiescentBoot_isStandby() throws RemoteException {
-        when(mIPowerManagerMock.isInteractive()).thenReturn(false);
+        mPowerManager.setInteractive(false);
         mHdmiControlServiceSpy.onBootPhase(PHASE_BOOT_COMPLETED);
         assertThat(mHdmiControlServiceSpy.getPowerStatus()).isEqualTo(
                 HdmiControlManager.POWER_STATUS_STANDBY);
@@ -785,30 +668,6 @@
         assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue();
     }
 
-    private static class HdmiControlStatusCallback extends IHdmiControlStatusChangeListener.Stub {
-        boolean mCecEnabled = false;
-        boolean mCecAvailable = false;
-
-        @Override
-        public void onStatusChange(int isCecEnabled, boolean isCecAvailable)
-                throws RemoteException {
-            mCecEnabled = isCecEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
-            mCecAvailable = isCecAvailable;
-        }
-    }
-
-    private static class VolumeControlFeatureCallback extends
-            IHdmiCecVolumeControlFeatureListener.Stub {
-        boolean mCallbackReceived = false;
-        int mVolumeControlEnabled = -1;
-
-        @Override
-        public void onHdmiCecVolumeControlFeature(int enabled) throws RemoteException {
-            this.mCallbackReceived = true;
-            this.mVolumeControlEnabled = enabled;
-        }
-    }
-
     @Test
     public void handleCecCommand_errorParameter_returnsAbortInvalidOperand() {
         // Validity ERROR_PARAMETER. Taken from HdmiCecMessageValidatorTest#isValid_menuStatus
@@ -1011,4 +870,134 @@
                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
     }
 
+    protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
+
+        private boolean mCanGoToStandby;
+        private boolean mIsStandby;
+        private boolean mIsDisabled;
+
+        MockPlaybackDevice(HdmiControlService service) {
+            super(service);
+        }
+
+        @Override
+        protected void onAddressAllocated(int logicalAddress, int reason) {
+        }
+
+        @Override
+        protected int getPreferredAddress() {
+            return 0;
+        }
+
+        @Override
+        protected void setPreferredAddress(int addr) {
+        }
+
+        @Override
+        protected boolean canGoToStandby() {
+            return mCanGoToStandby;
+        }
+
+        @Override
+        protected void disableDevice(
+                boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
+            mIsDisabled = true;
+            originalCallback.onCleared(this);
+        }
+
+        @Override
+        protected void onStandby(boolean initiatedByCec, int standbyAction) {
+            mIsStandby = true;
+        }
+
+        protected boolean isStandby() {
+            return mIsStandby;
+        }
+
+        protected boolean isDisabled() {
+            return mIsDisabled;
+        }
+
+        protected void setCanGoToStandby(boolean canGoToStandby) {
+            mCanGoToStandby = canGoToStandby;
+        }
+    }
+
+    protected static class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem {
+
+        private boolean mCanGoToStandby;
+        private boolean mIsStandby;
+        private boolean mIsDisabled;
+
+        MockAudioSystemDevice(HdmiControlService service) {
+            super(service);
+        }
+
+        @Override
+        protected void onAddressAllocated(int logicalAddress, int reason) {
+        }
+
+        @Override
+        protected int getPreferredAddress() {
+            return 0;
+        }
+
+        @Override
+        protected void setPreferredAddress(int addr) {
+        }
+
+        @Override
+        protected boolean canGoToStandby() {
+            return mCanGoToStandby;
+        }
+
+        @Override
+        protected void disableDevice(
+                boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
+            mIsDisabled = true;
+            originalCallback.onCleared(this);
+        }
+
+        @Override
+        protected void onStandby(boolean initiatedByCec, int standbyAction) {
+            mIsStandby = true;
+        }
+
+        protected boolean isStandby() {
+            return mIsStandby;
+        }
+
+        protected boolean isDisabled() {
+            return mIsDisabled;
+        }
+
+        protected void setCanGoToStandby(boolean canGoToStandby) {
+            mCanGoToStandby = canGoToStandby;
+        }
+    }
+
+    private static class HdmiControlStatusCallback extends IHdmiControlStatusChangeListener.Stub {
+        boolean mCecEnabled = false;
+        boolean mCecAvailable = false;
+
+        @Override
+        public void onStatusChange(int isCecEnabled, boolean isCecAvailable)
+                throws RemoteException {
+            mCecEnabled = isCecEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
+            mCecAvailable = isCecAvailable;
+        }
+    }
+
+    private static class VolumeControlFeatureCallback extends
+            IHdmiCecVolumeControlFeatureListener.Stub {
+        boolean mCallbackReceived = false;
+        int mVolumeControlEnabled = -1;
+
+        @Override
+        public void onHdmiCecVolumeControlFeature(int enabled) throws RemoteException {
+            this.mCallbackReceived = true;
+            this.mVolumeControlEnabled = enabled;
+        }
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index d5b116f..5074f64 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -23,7 +23,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -31,11 +30,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.media.AudioManager;
-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;
@@ -46,8 +41,6 @@
 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.Collections;
@@ -69,36 +62,22 @@
     private Context mContextSpy;
     private HdmiControlService mHdmiControlService;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private FakeHdmiCecConfig mHdmiCecConfig;
 
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private int mPhysicalAddress;
 
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
-
     /**
      * Manually called before tests, because some tests require HDMI control to be disabled.
      * @param hdmiControlEnabled whether to enable the global setting hdmi_control.
      * @throws Exception
      */
     public void setUp(boolean hdmiControlEnabled) throws Exception {
-        MockitoAnnotations.initMocks(this);
-
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
             AudioManager getAudioManager() {
@@ -112,21 +91,11 @@
             }
 
             @Override
-            void wakeUp() {
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
 
             @Override
-            protected PowerManager getPowerManager() {
-                return new PowerManager(mContextSpy, mIPowerManagerMock,
-                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-            }
-
-            @Override
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
@@ -143,6 +112,8 @@
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mPhysicalAddress = 0x2000;
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
         mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index 60c0f41..a12aa29 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -24,7 +24,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -32,11 +31,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.media.AudioManager;
-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;
@@ -46,8 +41,6 @@
 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.Collections;
@@ -61,31 +54,17 @@
     private Context mContextSpy;
     private HdmiControlService mHdmiControlService;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
 
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private int mPhysicalAddress;
     private HdmiCecLocalDeviceTv mTvDevice;
 
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
-
         mHdmiControlService = new HdmiControlService(mContextSpy,
                 Collections.singletonList(HdmiDeviceInfo.DEVICE_TV)) {
             @Override
@@ -100,21 +79,11 @@
             }
 
             @Override
-            void wakeUp() {
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
 
             @Override
-            protected PowerManager getPowerManager() {
-                return new PowerManager(mContextSpy, mIPowerManagerMock,
-                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-            }
-
-            @Override
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
@@ -140,6 +109,8 @@
                 new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false);
         mNativeWrapper.setPortInfo(hdmiPortInfo);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mPhysicalAddress = 0x0000;
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
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..9589b73
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
@@ -0,0 +1,577 @@
+/*
+ * 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.Looper;
+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 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 FakePowerManagerWrapper mPowerManager;
+    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;
+                }
+            };
+
+    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() {
+        Context context = InstrumentationRegistry.getTargetContext();
+        mMyLooper = mTestLooper.getLooper();
+
+        mHdmiControlService =
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
+                    @Override
+                    boolean isControlEnabled() {
+                        return true;
+                    }
+
+                    @Override
+                    protected void writeStringSystemProperty(String key, String value) {
+                        // do nothing
+                    }
+
+                    @Override
+                    boolean isPowerStandbyOrTransient() {
+                        return false;
+                    }
+                };
+
+        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();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
+        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/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
index bd307fd..0916b12 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
@@ -33,11 +33,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
-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;
@@ -49,8 +45,6 @@
 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.Collections;
@@ -101,9 +95,9 @@
     private static final int VENDOR_ID_AVR = 0x11233;
 
     private static final byte[] TUNER_PARAM =
-            new byte[] {(PHYSICAL_ADDRESS_TUNER >> 8) & 0xFF, PHYSICAL_ADDRESS_TUNER & 0xFF};
+            new byte[]{(PHYSICAL_ADDRESS_TUNER >> 8) & 0xFF, PHYSICAL_ADDRESS_TUNER & 0xFF};
     private static final byte[] PLAYER_PARAM =
-            new byte[] {(PHYSICAL_ADDRESS_PLAYER >> 8) & 0xFF, PHYSICAL_ADDRESS_PLAYER & 0xFF};
+            new byte[]{(PHYSICAL_ADDRESS_PLAYER >> 8) & 0xFF, PHYSICAL_ADDRESS_PLAYER & 0xFF};
 
     private static final HdmiDeviceInfo DEVICE_INFO_AVR =
             new HdmiDeviceInfo(ADDR_AUDIO_SYSTEM, PHYSICAL_ADDRESS_AVR, PORT_1,
@@ -124,23 +118,20 @@
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
 
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
+    private static RoutingControlAction createRoutingControlAction(HdmiCecLocalDeviceTv localDevice,
+            TestInputSelectCallback callback) {
+        return new RoutingControlAction(localDevice, PHYSICAL_ADDRESS_AVR, callback);
+    }
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mMyLooper));
 
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
 
@@ -153,10 +144,6 @@
                     }
 
                     @Override
-                    void wakeUp() {
-                    }
-
-                    @Override
                     protected void writeStringSystemProperty(String key, String value) {
                         // do nothing
                     }
@@ -167,11 +154,6 @@
                     }
 
                     @Override
-                    protected PowerManager getPowerManager() {
-                        return powerManager;
-                    }
-
-                    @Override
                     protected HdmiCecConfig getHdmiCecConfig() {
                         return hdmiCecConfig;
                     }
@@ -190,9 +172,11 @@
         HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
         hdmiPortInfos[0] =
                 new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_AVR,
-                                 true, false, false);
+                        true, false, false);
         mNativeWrapper.setPortInfo(hdmiPortInfos);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mNativeWrapper.setPhysicalAddress(0x0000);
         mTestLooper.dispatchAll();
@@ -200,6 +184,50 @@
         mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR);
     }
 
+    // Routing control succeeds against the device connected directly to the port. Action
+    // won't get any <Routing Information> in this case. It times out on <Routing Information>,
+    // regards the directly connected one as the new routing path to switch to.
+    @Test
+    public void testRoutingControl_succeedForDirectlyConnectedDevice() {
+        TestInputSelectCallback callback = new TestInputSelectCallback();
+        TestActionTimer actionTimer = new TestActionTimer();
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR);
+
+        RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback);
+        action.setActionTimer(actionTimer);
+        action.start();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION);
+
+        action.handleTimerEvent(actionTimer.getState());
+        mTestLooper.dispatchAll();
+        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+                ADDR_TV, PHYSICAL_ADDRESS_AVR);
+        assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+    }
+
+    // Succeeds by receiving a couple of <Routing Information> commands, followed by
+    // <Set Stream Path> going out in the end.
+    @Test
+    public void testRoutingControl_succeedForDeviceBehindSwitch() {
+        TestInputSelectCallback callback = new TestInputSelectCallback();
+        TestActionTimer actionTimer = new TestActionTimer();
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_PLAYER);
+        RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback);
+        action.setActionTimer(actionTimer);
+        action.start();
+
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION);
+
+        action.processCommand(ROUTING_INFORMATION_TUNER);
+        action.processCommand(ROUTING_INFORMATION_PLAYER);
+
+        action.handleTimerEvent(actionTimer.getState());
+        mTestLooper.dispatchAll();
+        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+                ADDR_TV, PHYSICAL_ADDRESS_PLAYER);
+        assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+    }
+
     private static class TestActionTimer implements ActionTimer {
         private int mState;
 
@@ -230,53 +258,4 @@
             return mCallbackResult.get(0);
         }
     }
-
-    private static RoutingControlAction createRoutingControlAction(HdmiCecLocalDeviceTv localDevice,
-            TestInputSelectCallback callback) {
-        return new RoutingControlAction(localDevice, PHYSICAL_ADDRESS_AVR, callback);
-    }
-
-    // Routing control succeeds against the device connected directly to the port. Action
-    // won't get any <Routing Information> in this case. It times out on <Routing Information>,
-    // regards the directly connected one as the new routing path to switch to.
-    @Test
-    public void testRoutingControl_succeedForDirectlyConnectedDevice() {
-        TestInputSelectCallback callback = new TestInputSelectCallback();
-        TestActionTimer actionTimer = new TestActionTimer();
-        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR);
-
-        RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback);
-        action.setActionTimer(actionTimer);
-        action.start();
-        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION);
-
-        action.handleTimerEvent(actionTimer.getState());
-        mTestLooper.dispatchAll();
-        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
-                        ADDR_TV, PHYSICAL_ADDRESS_AVR);
-        assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
-    }
-
-    // Succeeds by receiving a couple of <Routing Information> commands, followed by
-    // <Set Stream Path> going out in the end.
-    @Test
-    public void testRoutingControl_succeedForDeviceBehindSwitch() {
-        TestInputSelectCallback callback = new TestInputSelectCallback();
-        TestActionTimer actionTimer = new TestActionTimer();
-        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_PLAYER);
-        RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback);
-        action.setActionTimer(actionTimer);
-        action.start();
-
-        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION);
-
-        action.processCommand(ROUTING_INFORMATION_TUNER);
-        action.processCommand(ROUTING_INFORMATION_PLAYER);
-
-        action.handleTimerEvent(actionTimer.getState());
-        mTestLooper.dispatchAll();
-        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
-                        ADDR_TV, PHYSICAL_ADDRESS_PLAYER);
-        assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
index c650f4b..949cf9f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
@@ -24,17 +24,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.media.AudioManager;
-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;
@@ -44,8 +39,6 @@
 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.Collections;
@@ -60,6 +53,7 @@
     private Context mContextSpy;
     private HdmiControlService mHdmiControlService;
     private FakeNativeWrapper mNativeWrapper;
+    private FakePowerManagerWrapper mPowerManager;
 
     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
 
@@ -67,25 +61,11 @@
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private int mPhysicalAddress;
 
-    @Mock
-    private IPowerManager mIPowerManagerMock;
-    @Mock
-    private IThermalService mIThermalServiceMock;
-
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
         Looper myLooper = mTestLooper.getLooper();
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(myLooper)));
-        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
-                new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(myLooper)));
-        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
@@ -100,21 +80,11 @@
             }
 
             @Override
-            void wakeUp() {
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
 
             @Override
-            protected PowerManager getPowerManager() {
-                return new PowerManager(mContextSpy, mIPowerManagerMock,
-                        mIThermalServiceMock, new Handler(myLooper));
-            }
-
-            @Override
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
@@ -137,6 +107,8 @@
                 new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true);
         mNativeWrapper.setPortInfo(hdmiPortInfos);
         mHdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+        mHdmiControlService.setPowerManager(mPowerManager);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mPhysicalAddress = 0x0000;
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index 3a8808b..b40650e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -47,6 +47,7 @@
 public class SystemAudioInitiationActionFromAvrTest {
 
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+    private FakePowerManagerWrapper mPowerManager;
     private TestLooper mTestLooper = new TestLooper();
 
     private boolean mShouldDispatchActiveSource;
@@ -143,9 +144,6 @@
                     }
 
                     @Override
-                    void wakeUp() {}
-
-                    @Override
                     int getPhysicalAddress() {
                         return 0;
                     }
@@ -175,6 +173,8 @@
                 hdmiControlService, nativeWrapper, hdmiControlService.getAtomWriter());
         hdmiControlService.setCecController(hdmiCecController);
         hdmiControlService.initService();
+        mPowerManager = new FakePowerManagerWrapper(context);
+        hdmiControlService.setPowerManager(mPowerManager);
         mHdmiCecLocalDeviceAudioSystem =
                 new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
                     @Override
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 29ff9f4..b793482 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -338,7 +338,7 @@
                 when(pkg.getBaseApkPath()).thenReturn(apkPath);
                 when(pkg.getLongVersionCode()).thenReturn((long) versionCode);
                 when(pkg.getOverlayTarget()).thenReturn(targetPackageName);
-                when(pkg.getOverlayTargetName()).thenReturn(targetOverlayableName);
+                when(pkg.getOverlayTargetOverlayableName()).thenReturn(targetOverlayableName);
                 when(pkg.getOverlayCategory()).thenReturn("Fake-category-" + targetPackageName);
                 return pkg;
             }
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/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index be942d6..9f12438 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -762,7 +762,7 @@
         ParsingPackage overlay = pkg("com.some.package.overlay")
                 .setOverlay(true)
                 .setOverlayTarget(target.getPackageName())
-                .setOverlayTargetName("overlayableName");
+                .setOverlayTargetOverlayableName("overlayableName");
         ParsingPackage actor = pkg("com.some.package.actor");
 
         final AppsFilter appsFilter = new AppsFilter(
@@ -787,7 +787,7 @@
                         if (overlay.getPackageName().equals(pkg.getPackageName())) {
                             Map<String, Set<String>> map = new ArrayMap<>();
                             Set<String> set = new ArraySet<>();
-                            set.add(overlay.getOverlayTargetName());
+                            set.add(overlay.getOverlayTargetOverlayableName());
                             map.put(overlay.getOverlayTarget(), set);
                             return map;
                         }
@@ -829,7 +829,7 @@
         assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
                 actorSetting, SYSTEM_USER));
 
-        appsFilter.removePackage(targetSetting);
+        appsFilter.removePackage(targetSetting, false /* isReplace */);
 
         // Actor loses visibility to the overlay via removal of the target
         assertTrue(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
@@ -847,7 +847,7 @@
         ParsingPackage overlay = pkg("com.some.package.overlay")
                 .setOverlay(true)
                 .setOverlayTarget(target.getPackageName())
-                .setOverlayTargetName("overlayableName");
+                .setOverlayTargetOverlayableName("overlayableName");
         ParsingPackage actorOne = pkg("com.some.package.actor.one");
         ParsingPackage actorTwo = pkg("com.some.package.actor.two");
 
@@ -874,7 +874,7 @@
                         if (overlay.getPackageName().equals(pkg.getPackageName())) {
                             Map<String, Set<String>> map = new ArrayMap<>();
                             Set<String> set = new ArraySet<>();
-                            set.add(overlay.getOverlayTargetName());
+                            set.add(overlay.getOverlayTargetOverlayableName());
                             map.put(overlay.getOverlayTarget(), set);
                             return map;
                         }
@@ -1074,7 +1074,8 @@
         watcher.verifyNoChangeReported("getVisibility");
 
         // provider read
-        appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+        appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId,
+                false /* retainOnUpdate */);
         watcher.verifyChangeReported("grantImplicitAccess");
 
         // ensure implicit access is included in the filter
@@ -1143,7 +1144,8 @@
         watcher.verifyNoChangeReported("get");
 
         // provider read
-        appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+        appsFilter.grantImplicitAccess(
+                hasProviderAppId, queriesProviderAppId, false /* retainOnUpdate */);
         watcher.verifyChangeReported("grantImplicitAccess");
 
         // ensure implicit access is included in the filter
@@ -1154,7 +1156,7 @@
         watcher.verifyNoChangeReported("get");
 
         // remove a package
-        appsFilter.removePackage(seesNothing);
+        appsFilter.removePackage(seesNothing, false /* isReplace */);
         watcher.verifyChangeReported("removePackage");
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
index 0f1b14b..0247590 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
@@ -35,7 +35,7 @@
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Build;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
 
 import org.junit.After;
 import org.junit.Before;
@@ -44,13 +44,13 @@
 public class CompatibilityModeTest {
 
     private boolean mCompatibilityModeEnabled;;
-    private AndroidPackage mMockAndroidPackage;
+    private PackageImpl mMockAndroidPackage;
     private PackageUserState mMockUserState;
 
     @Before
     public void setUp() {
         mCompatibilityModeEnabled = ParsingPackageUtils.sCompatibilityModeEnabled;
-        mMockAndroidPackage = mock(AndroidPackage.class);
+        mMockAndroidPackage = mock(PackageImpl.class);
         mMockUserState = mock(PackageUserState.class);
         mMockUserState.installed = true;
         when(mMockUserState.isAvailable(anyInt())).thenReturn(true);
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 f241fe1..dbed445 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -151,7 +151,7 @@
         String[] partitions = { "system", "vendor", "odm", "oem", "product", "system_ext" };
         String[] appdir = { "app", "priv-app" };
         for (int i = 0; i < partitions.length; i++) {
-            final PackageManagerService.ScanPartition scanPartition =
+            final ScanPartition scanPartition =
                     PackageManagerService.SYSTEM_PARTITIONS.get(i);
             for (int j = 0; j < appdir.length; j++) {
                 File path = new File(String.format("%s/%s/A.apk", partitions[i], appdir[j]));
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 45e2ab4..76741c4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -955,7 +955,6 @@
         assertSame(origPkgSetting.signatures, testPkgSetting.signatures);
         assertThat(origPkgSetting.signatures, is(testPkgSetting.signatures));
         assertThat(origPkgSetting.timeStamp, is(testPkgSetting.timeStamp));
-        assertThat(origPkgSetting.uidError, is(testPkgSetting.uidError));
         assertNotSame(origPkgSetting.getUserState(), is(testPkgSetting.getUserState()));
         // No equals() method for SparseArray object
         // assertThat(origPkgSetting.getUserState(), is(testPkgSetting.getUserState()));
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..0cbac87 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -56,6 +56,7 @@
 import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
 
@@ -71,6 +72,7 @@
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.TestPackageParser2;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 
@@ -174,7 +176,7 @@
                     true /* useCaches */).hideAsFinal();
 
             Parcel p = Parcel.obtain();
-            pkg.writeToParcel(p, 0 /* flags */);
+            ((Parcelable) pkg).writeToParcel(p, 0 /* flags */);
 
             p.setDataPosition(0);
             ParsedPackage deserialized = new PackageImpl(p);
@@ -191,7 +193,7 @@
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
-        pkg.writeToParcel(p, 0 /* flags */);
+        ((Parcelable) pkg).writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
         ParsedPackage deserialized = new PackageImpl(p);
@@ -204,7 +206,7 @@
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
-        pkg.writeToParcel(p, 0 /* flags */);
+        ((Parcelable) pkg).writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
         ParsingPackage deserialized = new PackageImpl(p);
@@ -609,10 +611,10 @@
     private static PackageSetting mockPkgSetting(AndroidPackage pkg) {
         return new PackageSettingBuilder()
                 .setName(pkg.getPackageName())
-                .setRealName(pkg.getRealPackage())
+                .setRealName(pkg.getManifestPackageName())
                 .setCodePath(pkg.getPath())
-                .setPrimaryCpuAbiString(pkg.getPrimaryCpuAbi())
-                .setSecondaryCpuAbiString(pkg.getSecondaryCpuAbi())
+                .setPrimaryCpuAbiString(AndroidPackageUtils.getRawPrimaryCpuAbi(pkg))
+                .setSecondaryCpuAbiString(AndroidPackageUtils.getRawSecondaryCpuAbi(pkg))
                 .setPVersionCode(pkg.getLongVersionCode())
                 .setPkgFlags(PackageInfoUtils.appInfoFlags(pkg, null))
                 .setPrivateFlags(PackageInfoUtils.appInfoPrivateFlags(pkg, null))
@@ -625,7 +627,7 @@
     public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) {
         assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
         assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated());
-        assertEquals(a.getVersionCode(), b.getVersionCode());
+        assertEquals(a.getLongVersionCode(), b.getLongVersionCode());
         assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel());
         assertEquals(a.getInstallLocation(), b.getInstallLocation());
         assertEquals(a.isCoreApp(), b.isCoreApp());
@@ -700,7 +702,7 @@
         assertEquals(a.getUsesLibraries(), b.getUsesLibraries());
         assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries());
         assertEquals(a.getOriginalPackages(), b.getOriginalPackages());
-        assertEquals(a.getRealPackage(), b.getRealPackage());
+        assertEquals(a.getManifestPackageName(), b.getManifestPackageName());
         assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions());
         assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
         assertEquals(a.getVersionName(), b.getVersionName());
@@ -710,7 +712,7 @@
         assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
         assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
         assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
-        assertEquals(a.getOverlayTargetName(), b.getOverlayTargetName());
+        assertEquals(a.getOverlayTargetOverlayableName(), b.getOverlayTargetOverlayableName());
         assertEquals(a.getOverlayCategory(), b.getOverlayCategory());
         assertEquals(a.getOverlayPriority(), b.getOverlayPriority());
         assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic());
@@ -928,7 +930,6 @@
                 .addUsesLibrary("foo11")
                 .addUsesOptionalLibrary("foo12")
                 .addOriginalPackage("foo14")
-                .setRealPackage("foo15")
                 .addAdoptPermission("foo16")
                 .setMetaData(bundle)
                 .setVersionName("foo17")
@@ -949,11 +950,11 @@
                 .addConfigPreference(new ConfigurationInfo())
                 .addReqFeature(new FeatureInfo())
                 .addFeatureGroup(new FeatureGroupInfo())
-                .setCompileSdkVersionCodename("foo23")
+                .setCompileSdkVersionCodeName("foo23")
                 .setCompileSdkVersion(100)
                 .setOverlayCategory("foo24")
                 .setOverlayIsStatic(true)
-                .setOverlayTargetName("foo26")
+                .setOverlayTargetOverlayableName("foo26")
                 .setVisibleToInstantApps(true)
                 .setSplitHasCode(0, true)
                 .hideAsParsed())
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 6c6cfd4..5de0c2b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -87,6 +87,8 @@
     PlatformCompat mMockCompatibility;
     @Mock
     PackageManagerService.Injector mMockInjector;
+    @Mock
+    PackageManagerService mMockPackageManager;
 
     @Before
     public void setupInjector() {
@@ -174,7 +176,7 @@
         final ScanRequest scanRequestNoRealPkg =
                 createBasicScanRequestBuilder(
                         createBasicPackage(DUMMY_PACKAGE_NAME)
-                                .setRealPackage("com.package.real"))
+                                .addOriginalPackage("com.package.real"))
                         .build();
 
         final ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
@@ -432,7 +434,7 @@
         final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
                 .addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
 
-        final ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+        final ScanResult scanResult = mMockPackageManager.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
                 mMockInjector,
                 true /*isUnderFactoryTest*/,
@@ -480,7 +482,7 @@
 
     private ScanResult executeScan(
             ScanRequest scanRequest) throws PackageManagerException {
-        ScanResult result = PackageManagerService.scanPackageOnlyLI(
+        ScanResult result = mMockPackageManager.scanPackageOnlyLI(
                 scanRequest,
                 mMockInjector,
                 false /*isUnderFactoryTest*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 16f72f7..2a7a2ff 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -140,7 +140,7 @@
         Collection<String> apkToDexMetadataList =
                 AndroidPackageUtils.getPackageDexMetadata(pkg).values();
         String packageName = pkg.getPackageName();
-        long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
+        long versionCode = pkg.getLongVersionCode();
         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
         for (String dexMetadata : apkToDexMetadataList) {
             final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
@@ -416,8 +416,11 @@
                         result.getErrorMessage(), result.getException());
             }
             final ApkLite baseApk = result.getResult();
-            final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk, null,
-                    null, null, null, null, null, baseApk.getTargetSdkVersion());
+            final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk,
+                    null /* splitNames */, null /* isFeatureSplits */, null /* usesSplitNames */,
+                    null /* configForSplit */, null /* splitApkPaths */,
+                    null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
+                    null /* requiredSplitTypes */, null /* splitTypes */);
             Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite));
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
index fb82b1d..51c268e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -105,7 +105,6 @@
     lateinit var param: Param<Any>
 
     @Test
-    @Ignore("b/155935153")
     fun fieldPresence() {
         oldPackages.asSequence().zip(newPackages.asSequence())
                 .forEach { (old, new) ->
@@ -128,7 +127,6 @@
     }
 
     @Test
-    @Ignore("b/155935153")
     fun fieldAbsence() {
         newPackages.forEach {
             val newWithoutFlag = param.newPkgFunction(it, 0)
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 b7eddb3..ae07f8e 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
@@ -183,6 +183,7 @@
             this.appId = aPkg.uid
             whenever(pkgState) { PackageStateUnserialized() }
             whenever(readUserState(anyInt())) { dummyUserState }
+            whenever(categoryOverride) { ApplicationInfo.CATEGORY_UNDEFINED }
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 4d2d2f1..8e2c1f0 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -150,8 +150,9 @@
         provider.setListener(listener);
 
         verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
-        final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, ""),
-                new DeviceState(2, "") };
+        final DeviceState[] expectedStates = new DeviceState[]{
+                new DeviceState(1, "", 0 /* flags */),
+                new DeviceState(2, "", 0 /* flags */) };
         assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
 
         verify(listener).onStateChanged(mIntegerCaptor.capture());
@@ -187,8 +188,9 @@
         provider.setListener(listener);
 
         verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
-        final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, ""),
-                new DeviceState(2, "CLOSED") };
+        final DeviceState[] expectedStates = new DeviceState[]{
+                new DeviceState(1, "", 0 /* flags */),
+                new DeviceState(2, "CLOSED", 0 /* flags */) };
         assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
 
         // onStateChanged() should not be called because the provider has not yet been notified of
@@ -264,8 +266,11 @@
 
         verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
         assertArrayEquals(
-                new DeviceState[]{ new DeviceState(1, "CLOSED"), new DeviceState(2, "HALF_OPENED"),
-                        new DeviceState(3, "OPENED") }, mDeviceStateArrayCaptor.getValue());
+                new DeviceState[]{
+                        new DeviceState(1, "CLOSED", 0 /* flags */),
+                        new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+                        new DeviceState(3, "OPENED", 0 /* flags */) },
+                mDeviceStateArrayCaptor.getValue());
         // onStateChanged() should not be called because the provider has not yet been notified of
         // the initial sensor state.
         verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
@@ -350,8 +355,10 @@
 
         verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
         assertArrayEquals(
-                new DeviceState[]{ new DeviceState(1, "CLOSED"), new DeviceState(2, "HALF_OPENED"),
-                        }, mDeviceStateArrayCaptor.getValue());
+                new DeviceState[]{
+                        new DeviceState(1, "CLOSED", 0 /* flags */),
+                        new DeviceState(2, "HALF_OPENED", 0 /* flags */)
+                }, mDeviceStateArrayCaptor.getValue());
         // onStateChanged() should be called because the provider could not find the sensor.
         verify(listener).onStateChanged(mIntegerCaptor.capture());
         assertEquals(1, mIntegerCaptor.getValue().intValue());
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
index 1947481..3f8cf9c 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -76,7 +76,7 @@
     public static Iterable<Object[]> data() {
         List<Object[]> result = new LinkedList<>();
 
-        for (String version : new String[]{"V2_0", "V2_1", "V2_2", "V2_3", "V2_4",}) {
+        for (String version : new String[]{"V2_0", "V2_1", "V2_2", "V2_3",}) {
             for (boolean concurrentCapture : new boolean[]{false, true}) {
                 result.add(new Object[]{version, concurrentCapture});
             }
@@ -113,9 +113,7 @@
                         || descriptor.equals("android.hardware.soundtrigger@2.2::ISoundTriggerHw")
                         && mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw
                         || descriptor.equals("android.hardware.soundtrigger@2.3::ISoundTriggerHw")
-                        && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw
-                        || descriptor.equals("android.hardware.soundtrigger@2.4::ISoundTriggerHw")
-                        && mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+                        && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
                     return mHalDriver;
                 }
                 return null;
@@ -269,44 +267,9 @@
         return handle;
     }
 
-    private int loadGenericModel_2_4(ISoundTriggerHal.ModelCallback canonicalCallback)
-            throws Exception {
-        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-
-        final int handle = 29;
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class);
-        ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback> callbackCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.class);
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadSoundModel_2_4Callback
-                    resultCallback = invocation.getArgument(2);
-
-            // This is the return of this method.
-            resultCallback.onValues(0, handle);
-            return null;
-        }).when(driver_2_4).loadSoundModel_2_4(any(), any(), any());
-
-        assertEquals(handle,
-                mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback));
-
-        verify(driver_2_4).loadSoundModel_2_4(modelCaptor.capture(), callbackCaptor.capture(),
-                any());
-
-        TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue());
-        validateCallback_2_4(callbackCaptor.getValue(), canonicalCallback);
-        return handle;
-    }
-
     private int loadGenericModel(ISoundTriggerHal.ModelCallback canonicalCallback)
             throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            return loadGenericModel_2_4(canonicalCallback);
-        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
             return loadGenericModel_2_1(canonicalCallback);
         } else {
             return loadGenericModel_2_0(canonicalCallback);
@@ -322,8 +285,6 @@
 
     @Test
     public void testMaxModels() throws Exception {
-        assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw);
-
         // Register global callback.
         ISoundTriggerHal.GlobalCallback globalCallback = mock(
                 ISoundTriggerHal.GlobalCallback.class);
@@ -358,37 +319,6 @@
         verify(globalCallback).onResourcesAvailable();
     }
 
-    private void testLoadGenericModelBusy_2_4() throws Exception {
-        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadSoundModel_2_4Callback
-                    resultCallback = invocation.getArgument(2);
-
-            // This is the return of this method.
-            resultCallback.onValues(-OsConstants.EBUSY, 0);
-            return null;
-        }).when(driver_2_4).loadSoundModel_2_4(any(), any(), any());
-
-        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
-                ISoundTriggerHal.ModelCallback.class);
-        try {
-            mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback);
-            fail("Expected an exception");
-        } catch (RecoverableException e) {
-            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
-        }
-        verify(driver_2_4).loadSoundModel_2_4(any(), any(), any());
-    }
-
-    @Test
-    public void testLoadGenericModelBusy() throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            testLoadGenericModelBusy_2_4();
-        }
-    }
-
     private int loadPhraseModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback)
             throws Exception {
         final int handle = 29;
@@ -452,43 +382,8 @@
         return handle;
     }
 
-    private int loadPhraseModel_2_4(ISoundTriggerHal.ModelCallback canonicalCallback)
-            throws Exception {
-        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-
-        final int handle = 29;
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel>
-                modelCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class);
-        ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback> callbackCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.class);
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadPhraseSoundModel_2_4Callback
-                    resultCallback = invocation.getArgument(2);
-
-            // This is the return of this method.
-            resultCallback.onValues(0, handle);
-            return null;
-        }).when(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any());
-
-        assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(),
-                canonicalCallback));
-
-        verify(driver_2_4).loadPhraseSoundModel_2_4(modelCaptor.capture(), callbackCaptor.capture(),
-                any());
-
-        TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue());
-        validateCallback_2_4(callbackCaptor.getValue(), canonicalCallback);
-        return handle;
-    }
-
     public int loadPhraseModel(ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            return loadPhraseModel_2_4(canonicalCallback);
-        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
             return loadPhraseModel_2_1(canonicalCallback);
         } else {
             return loadPhraseModel_2_0(canonicalCallback);
@@ -502,37 +397,6 @@
         loadPhraseModel(canonicalCallback);
     }
 
-    private void testLoadPhraseModelBusy_2_4() throws Exception {
-        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadPhraseSoundModel_2_4Callback
-                    resultCallback = invocation.getArgument(2);
-
-            // This is the return of this method.
-            resultCallback.onValues(-OsConstants.EBUSY, 0);
-            return null;
-        }).when(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any());
-
-        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
-                ISoundTriggerHal.ModelCallback.class);
-        try {
-            mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(), canonicalCallback);
-            fail("Expected an exception");
-        } catch (RecoverableException e) {
-            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
-        }
-        verify(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any());
-    }
-
-    @Test
-    public void testLoadPhraseModelBusy() throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            testLoadPhraseModelBusy_2_4();
-        }
-    }
-
     @Test
     public void testUnloadModel() throws Exception {
         mCanonical.unloadSoundModel(14);
@@ -596,25 +460,9 @@
         TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 808, 909);
     }
 
-    private void startRecognition_2_4(int handle) throws Exception {
-        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-        ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> configCaptor =
-                ArgumentCaptor.forClass(android.hardware.soundtrigger.V2_3.RecognitionConfig.class);
-
-        when(driver_2_4.startRecognition_2_4(eq(handle), any())).thenReturn(0);
-
-        RecognitionConfig config = TestUtil.createRecognitionConfig();
-        mCanonical.startRecognition(handle, 21, 22, config);
-        verify(driver_2_4).startRecognition_2_4(eq(handle), configCaptor.capture());
-        TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 21, 22);
-    }
-
     private void startRecognition(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)
             throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            startRecognition_2_4(handle);
-        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
             startRecognition_2_3(handle);
         } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
             startRecognition_2_1(handle, canonicalCallback);
@@ -634,41 +482,9 @@
         startRecognition(handle, canonicalCallback);
     }
 
-    private void testStartRecognitionBusy_2_4() throws Exception {
-        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-
-        final int handle = 68;
-        when(driver_2_4.startRecognition_2_4(eq(handle), any())).thenReturn(-OsConstants.EBUSY);
-
-        RecognitionConfig config = TestUtil.createRecognitionConfig();
-        try {
-            mCanonical.startRecognition(handle, 34, 35, config);
-            fail("Expected an exception");
-        } catch (RecoverableException e) {
-            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
-        }
-        verify(driver_2_4).startRecognition_2_4(eq(handle), any());
-    }
-
-    @Test
-    public void testStartRecognitionBusy() throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            testStartRecognitionBusy_2_4();
-        }
-    }
-
-    @Test
-    public void testNoRegisterCaptureStateListener() {
-        assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw
-                || mSupportConcurrentCapture);
-        verify(mCaptureStateNotifier, never()).registerListener(any());
-    }
-
     @Test
     public void testConcurrentCaptureAbort() throws Exception {
-        assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw
-                || mSupportConcurrentCapture);
+        assumeFalse(mSupportConcurrentCapture);
         verify(mCaptureStateNotifier, atLeast(1)).registerListener(any());
 
         // Register global callback.
@@ -707,8 +523,7 @@
 
     @Test
     public void testConcurrentCaptureReject() throws Exception {
-        assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw
-                || mSupportConcurrentCapture);
+        assumeFalse(mSupportConcurrentCapture);
         verify(mCaptureStateNotifier, atLeast(1)).registerListener(any());
 
         // Register global callback.
@@ -858,28 +673,9 @@
         // We just care that it doesn't throw.
     }
 
-    private void testGlobalCallback_2_4() throws Exception {
-        android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
-                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
-
-        ISoundTriggerHal.GlobalCallback canonicalCallback = mock(
-                ISoundTriggerHal.GlobalCallback.class);
-        mCanonical.registerCallback(canonicalCallback);
-
-        ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback>
-                callbackCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback.class);
-        verify(driver_2_4).registerGlobalCallback(callbackCaptor.capture());
-        validateGlobalCallback_2_4(callbackCaptor.getValue(), canonicalCallback);
-    }
-
     @Test
     public void testGlobalCallback() throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
-            testGlobalCallback_2_4();
-        } else {
-            testGlobalCallback_2_0();
-        }
+        testGlobalCallback_2_0();
     }
 
     @Test
@@ -908,14 +704,6 @@
         verify(mHalDriver).interfaceDescriptor();
     }
 
-    private void validateGlobalCallback_2_4(
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback hwCallback,
-            ISoundTriggerHal.GlobalCallback canonicalCallback) throws Exception {
-        hwCallback.onResourcesAvailable();
-        mCanonical.flushCallbacks();
-        verify(canonicalCallback).onResourcesAvailable();
-    }
-
     private void validateCallback_2_0(
             android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback hwCallback,
             ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
@@ -985,48 +773,6 @@
         clearInvocations(canonicalCallback);
     }
 
-    private void validateCallback_2_4(
-            android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback hwCallback,
-            ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
-        {
-            final int handle = 85;
-            final int status =
-                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
-            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    RecognitionEvent.class);
-
-            hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
-                    99);
-            mCanonical.flushCallbacks();
-            verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED);
-        }
-
-        {
-            final int handle = 92;
-            final int status =
-                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
-            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    PhraseRecognitionEvent.class);
-
-            hwCallback.phraseRecognitionCallback_2_1(
-                    TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
-            mCanonical.flushCallbacks();
-            verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
-                    RecognitionStatus.SUCCESS);
-        }
-
-        {
-            final int handle = 23;
-            hwCallback.modelUnloaded(handle);
-            mCanonical.flushCallbacks();
-            verify(canonicalCallback).modelUnloaded(handle);
-        }
-        verifyNoMoreInteractions(canonicalCallback);
-        clearInvocations(canonicalCallback);
-    }
-
     public static class CaptureStateNotifier implements ICaptureStateNotifier {
         private final List<Listener> mListeners = new LinkedList<>();
 
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
index 4eca298..39815b7 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
@@ -22,10 +22,14 @@
 
 import android.annotation.NonNull;
 import android.hardware.soundtrigger.V2_1.ISoundTriggerHw;
-import android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback;
-import android.media.audio.common.AudioChannelMask;
+import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
+import android.media.AudioFormat;
+import android.media.MediaFormat;
+import android.media.audio.common.AudioChannelLayout;
 import android.media.audio.common.AudioConfig;
-import android.media.audio.common.AudioFormat;
+import android.media.audio.common.AudioConfigBase;
+import android.media.audio.common.AudioFormatDescription;
+import android.media.audio.common.AudioFormatType;
 import android.media.soundtrigger.AudioCapabilities;
 import android.media.soundtrigger.ConfidenceLevel;
 import android.media.soundtrigger.Phrase;
@@ -53,6 +57,8 @@
  * corresponding objects generated by the system under test.
  */
 class TestUtil {
+    private static final int AUDIO_FORMAT_MP3 = 0x01000000;  // matches native
+
     static SoundModel createGenericSoundModel() {
         return createSoundModel(SoundModelType.GENERIC);
     }
@@ -310,8 +316,8 @@
         halEvent.capturePreambleMs = 345;
         halEvent.triggerInData = true;
         halEvent.audioConfig.sampleRateHz = 456;
-        halEvent.audioConfig.channelMask = AudioChannelMask.IN_LEFT;
-        halEvent.audioConfig.format = AudioFormat.MP3;
+        halEvent.audioConfig.channelMask = AudioFormat.CHANNEL_IN_MONO;  // matches native
+        halEvent.audioConfig.format = AUDIO_FORMAT_MP3;
         // hwEvent.audioConfig.offloadInfo is irrelevant.
         halEvent.data.add((byte) 31);
         halEvent.data.add((byte) 32);
@@ -319,6 +325,13 @@
         return halEvent;
     }
 
+    static AudioFormatDescription createAudioFormatMp3() {
+        AudioFormatDescription format = new AudioFormatDescription();
+        format.type = AudioFormatType.NON_PCM;
+        format.encoding = MediaFormat.MIMETYPE_AUDIO_MPEG;  // MP3
+        return format;
+    }
+
     static RecognitionEvent createRecognitionEvent(@RecognitionStatus int status) {
         RecognitionEvent event = new RecognitionEvent();
         event.status = status;
@@ -328,9 +341,11 @@
         event.capturePreambleMs = 345;
         event.triggerInData = true;
         event.audioConfig = new AudioConfig();
-        event.audioConfig.sampleRateHz = 456;
-        event.audioConfig.channelMask = AudioChannelMask.IN_LEFT;
-        event.audioConfig.format = AudioFormat.MP3;
+        event.audioConfig.base = new AudioConfigBase();
+        event.audioConfig.base.sampleRate = 456;
+        event.audioConfig.base.channelMask = AudioChannelLayout.layoutMask(
+                AudioChannelLayout.LAYOUT_MONO);
+        event.audioConfig.base.format = createAudioFormatMp3();
         //event.audioConfig.offloadInfo is irrelevant.
         event.data = new byte[]{31, 32, 33};
         return event;
@@ -354,9 +369,10 @@
         assertEquals(234, event.captureDelayMs);
         assertEquals(345, event.capturePreambleMs);
         assertTrue(event.triggerInData);
-        assertEquals(456, event.audioConfig.sampleRateHz);
-        assertEquals(AudioChannelMask.IN_LEFT, event.audioConfig.channelMask);
-        assertEquals(AudioFormat.MP3, event.audioConfig.format);
+        assertEquals(456, event.audioConfig.base.sampleRate);
+        assertEquals(AudioChannelLayout.layoutMask(AudioChannelLayout.LAYOUT_MONO),
+                event.audioConfig.base.channelMask);
+        assertEquals(createAudioFormatMp3(), event.audioConfig.base.format);
         assertArrayEquals(new byte[]{31, 32, 33}, event.data);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/tare/AgentTest.java b/services/tests/servicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
similarity index 96%
rename from services/tests/servicestests/src/com/android/server/tare/AgentTest.java
rename to services/tests/servicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
index 546b84a..b1b53fc 100644
--- a/services/tests/servicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/servicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
@@ -40,10 +40,10 @@
 
 import java.util.List;
 
-/** Tests various aspects of the Agent. */
+/** Tests the TrendCalculator in the Agent. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class AgentTest {
+public class AgentTrendCalculatorTest {
 
     private MockEconomicPolicy mEconomicPolicy;
 
@@ -98,7 +98,7 @@
     }
 
     @Test
-    public void testTrendCalculator_NoOngoingEvents() {
+    public void testNoOngoingEvents() {
         TrendCalculator trendCalculator = new TrendCalculator();
         mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT, 20);
 
@@ -128,7 +128,7 @@
     }
 
     @Test
-    public void testTrendCalculator_NoAffordabilityNotes() {
+    public void testNoAffordabilityNotes() {
         TrendCalculator trendCalculator = new TrendCalculator();
 
         OngoingEvent[] events = new OngoingEvent[]{
@@ -165,7 +165,7 @@
     }
 
     @Test
-    public void testTrendCalculator_NoTrendToThreshold() {
+    public void testNoTrendToThreshold() {
         TrendCalculator trendCalculator = new TrendCalculator();
         mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 10);
 
@@ -213,7 +213,7 @@
     }
 
     @Test
-    public void testTrendCalculator_SimpleTrendToThreshold() {
+    public void testSimpleTrendToThreshold() {
         TrendCalculator trendCalculator = new TrendCalculator();
         mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
 
@@ -257,7 +257,7 @@
     }
 
     @Test
-    public void testTrendCalculator_SelectCorrectThreshold() {
+    public void testSelectCorrectThreshold() {
         TrendCalculator trendCalculator = new TrendCalculator();
         mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
         mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 15);
@@ -307,7 +307,7 @@
     }
 
     @Test
-    public void testTrendCalculator_TrendsToBothThresholds() {
+    public void testTrendsToBothThresholds() {
         TrendCalculator trendCalculator = new TrendCalculator();
         mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
         mEconomicPolicy.mEventCosts.put(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK, 50);
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/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/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index 25b51da..e418d2f 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -73,8 +73,8 @@
 
     // we expect the following only during grant if a grant is expected
     private void verifyNoVisibilityGrant() {
-        verify(mContext.mPmInternal, never())
-                .grantImplicitAccess(anyInt(), any(), anyInt(), anyInt(), anyBoolean());
+        verify(mContext.mPmInternal, never()).grantImplicitAccess(
+                anyInt(), any(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Before
diff --git a/services/tests/servicestests/src/com/android/server/uwb/OWNERS b/services/tests/servicestests/src/com/android/server/uwb/OWNERS
deleted file mode 100644
index c31a2f1..0000000
--- a/services/tests/servicestests/src/com/android/server/uwb/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/base:/core/java/android/uwb/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java
deleted file mode 100644
index 11554c7..0000000
--- a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java
+++ /dev/null
@@ -1,365 +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.server.uwb;
-
-import static android.Manifest.permission.UWB_PRIVILEGED;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.PersistableBundle;
-import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.uwb.IUwbAdapter;
-import android.uwb.IUwbAdapterStateCallbacks;
-import android.uwb.IUwbRangingCallbacks;
-import android.uwb.RangingReport;
-import android.uwb.RangingSession;
-import android.uwb.SessionHandle;
-
-import androidx.test.runner.AndroidJUnit4;
-
-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;
-
-/**
- * Tests for {@link UwbServiceImpl}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-@Presubmit
-public class UwbServiceImplTest {
-    private static final int UID = 343453;
-    private static final String PACKAGE_NAME = "com.uwb.test";
-    private static final AttributionSource ATTRIBUTION_SOURCE =
-            new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build();
-
-    @Mock private IUwbAdapter mVendorService;
-    @Mock private IBinder mVendorServiceBinder;
-    @Mock private Context mContext;
-    @Mock private UwbInjector mUwbInjector;
-    @Captor private ArgumentCaptor<IUwbRangingCallbacks> mRangingCbCaptor;
-    @Captor private ArgumentCaptor<IBinder.DeathRecipient> mClientDeathCaptor;
-    @Captor private ArgumentCaptor<IBinder.DeathRecipient> mVendorServiceDeathCaptor;
-
-    private UwbServiceImpl mUwbServiceImpl;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        when(mUwbInjector.getVendorService()).thenReturn(mVendorService);
-        when(mUwbInjector.checkUwbRangingPermissionForDataDelivery(any(), any())).thenReturn(true);
-        when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder);
-        mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector);
-    }
-
-    @Test
-    public void testApiCallThrowsIllegalStateExceptionIfVendorServiceNotFound() throws Exception {
-        when(mUwbInjector.getVendorService()).thenReturn(null);
-
-        final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
-        try {
-            mUwbServiceImpl.registerAdapterStateCallbacks(cb);
-            fail();
-        } catch (IllegalStateException e) { /* pass */ }
-    }
-
-    @Test
-    public void testRegisterAdapterStateCallbacks() throws Exception {
-        final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
-        mUwbServiceImpl.registerAdapterStateCallbacks(cb);
-
-        verify(mVendorService).registerAdapterStateCallbacks(cb);
-    }
-
-    @Test
-    public void testUnregisterAdapterStateCallbacks() throws Exception {
-        final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
-        mUwbServiceImpl.unregisterAdapterStateCallbacks(cb);
-
-        verify(mVendorService).unregisterAdapterStateCallbacks(cb);
-    }
-
-    @Test
-    public void testGetTimestampResolutionNanos() throws Exception {
-        final long timestamp = 34L;
-        when(mVendorService.getTimestampResolutionNanos()).thenReturn(timestamp);
-        assertThat(mUwbServiceImpl.getTimestampResolutionNanos()).isEqualTo(timestamp);
-
-        verify(mVendorService).getTimestampResolutionNanos();
-    }
-
-    @Test
-    public void testGetSpecificationInfo() throws Exception {
-        final PersistableBundle specification = new PersistableBundle();
-        when(mVendorService.getSpecificationInfo()).thenReturn(specification);
-        assertThat(mUwbServiceImpl.getSpecificationInfo()).isEqualTo(specification);
-
-        verify(mVendorService).getSpecificationInfo();
-    }
-
-    @Test
-    public void testOpenRanging() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
-        final PersistableBundle parameters = new PersistableBundle();
-        final IBinder cbBinder = mock(IBinder.class);
-        when(cb.asBinder()).thenReturn(cbBinder);
-
-        mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters);
-
-        verify(mVendorService).openRanging(
-                eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(),
-                eq(parameters));
-        assertThat(mRangingCbCaptor.getValue()).isNotNull();
-    }
-
-    @Test
-    public void testStartRanging() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final PersistableBundle parameters = new PersistableBundle();
-
-        mUwbServiceImpl.startRanging(sessionHandle, parameters);
-
-        verify(mVendorService).startRanging(sessionHandle, parameters);
-    }
-
-    @Test
-    public void testReconfigureRanging() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final PersistableBundle parameters = new PersistableBundle();
-
-        mUwbServiceImpl.reconfigureRanging(sessionHandle, parameters);
-
-        verify(mVendorService).reconfigureRanging(sessionHandle, parameters);
-    }
-
-    @Test
-    public void testStopRanging() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-
-        mUwbServiceImpl.stopRanging(sessionHandle);
-
-        verify(mVendorService).stopRanging(sessionHandle);
-    }
-
-    @Test
-    public void testCloseRanging() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-
-        mUwbServiceImpl.closeRanging(sessionHandle);
-
-        verify(mVendorService).closeRanging(sessionHandle);
-    }
-
-    @Test
-    public void testRangingCallbacks() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
-        final PersistableBundle parameters = new PersistableBundle();
-        final IBinder cbBinder = mock(IBinder.class);
-        when(cb.asBinder()).thenReturn(cbBinder);
-
-        mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters);
-
-        verify(mVendorService).openRanging(
-                eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(),
-                eq(parameters));
-        assertThat(mRangingCbCaptor.getValue()).isNotNull();
-
-        // Invoke vendor service callbacks and ensure that the corresponding app callback is
-        // invoked.
-        mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
-        verify(cb).onRangingOpened(sessionHandle);
-
-        mRangingCbCaptor.getValue().onRangingOpenFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-        verify(cb).onRangingOpenFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-
-        mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters);
-        verify(cb).onRangingStarted(sessionHandle, parameters);
-
-        mRangingCbCaptor.getValue().onRangingStartFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-        verify(cb).onRangingStartFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-
-        mRangingCbCaptor.getValue().onRangingReconfigured(sessionHandle, parameters);
-        verify(cb).onRangingReconfigured(sessionHandle, parameters);
-
-        mRangingCbCaptor.getValue().onRangingReconfigureFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-        verify(cb).onRangingReconfigureFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-
-        mRangingCbCaptor.getValue().onRangingStopped(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-        verify(cb).onRangingStopped(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-
-        mRangingCbCaptor.getValue().onRangingStopFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-        verify(cb).onRangingStopFailed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-
-        final RangingReport rangingReport = new RangingReport.Builder().build();
-        mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport);
-        verify(cb).onRangingResult(sessionHandle, rangingReport);
-
-        mRangingCbCaptor.getValue().onRangingClosed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-        verify(cb).onRangingClosed(
-                sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
-    }
-
-    @Test
-    public void testHandleClientDeath() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
-        final PersistableBundle parameters = new PersistableBundle();
-        final IBinder cbBinder = mock(IBinder.class);
-        when(cb.asBinder()).thenReturn(cbBinder);
-
-        mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters);
-
-        verify(mVendorService).openRanging(
-                eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(),
-                eq(parameters));
-        assertThat(mRangingCbCaptor.getValue()).isNotNull();
-
-        verify(cbBinder).linkToDeath(mClientDeathCaptor.capture(), anyInt());
-        assertThat(mClientDeathCaptor.getValue()).isNotNull();
-
-        clearInvocations(cb);
-
-        // Invoke cb, ensure it reaches the client.
-        mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
-        verify(cb).onRangingOpened(sessionHandle);
-
-        // Trigger client death and ensure the session is stopped.
-        mClientDeathCaptor.getValue().binderDied();
-        verify(mVendorService).stopRanging(sessionHandle);
-        verify(mVendorService).closeRanging(sessionHandle);
-
-        // Invoke cb, it should be ignored.
-        mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters);
-        verify(cb, never()).onRangingStarted(any(), any());
-    }
-
-    @Test
-    public void testHandleVendorServiceDeath() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
-        final PersistableBundle parameters = new PersistableBundle();
-        final IBinder cbBinder = mock(IBinder.class);
-        when(cb.asBinder()).thenReturn(cbBinder);
-
-        mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters);
-
-        verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt());
-        assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull();
-
-        verify(mVendorService).openRanging(
-                eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(),
-                eq(parameters));
-        assertThat(mRangingCbCaptor.getValue()).isNotNull();
-
-        clearInvocations(cb);
-
-        // Invoke cb, ensure it reaches the client.
-        mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
-        verify(cb).onRangingOpened(sessionHandle);
-
-        // Trigger vendor service death and ensure that the client is informed of session end.
-        mVendorServiceDeathCaptor.getValue().binderDied();
-        verify(cb).onRangingClosed(
-                eq(sessionHandle), eq(RangingSession.Callback.REASON_UNKNOWN),
-                argThat((p) -> p.isEmpty()));
-    }
-
-    @Test
-    public void testThrowSecurityExceptionWhenCalledWithoutUwbPrivilegedPermission()
-            throws Exception {
-        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
-                eq(UWB_PRIVILEGED), any());
-        final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
-        try {
-            mUwbServiceImpl.registerAdapterStateCallbacks(cb);
-            fail();
-        } catch (SecurityException e) { /* pass */ }
-    }
-
-    @Test
-    public void testThrowSecurityExceptionWhenOpenRangingCalledWithoutUwbRangingPermission()
-            throws Exception {
-        doThrow(new SecurityException()).when(mUwbInjector).enforceUwbRangingPermissionForPreflight(
-                any());
-
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
-        final PersistableBundle parameters = new PersistableBundle();
-        final IBinder cbBinder = mock(IBinder.class);
-        when(cb.asBinder()).thenReturn(cbBinder);
-        try {
-            mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters);
-            fail();
-        } catch (SecurityException e) { /* pass */ }
-    }
-
-    @Test
-    public void testOnRangingResultCallbackNotSentWithoutUwbRangingPermission() throws Exception {
-        final SessionHandle sessionHandle = new SessionHandle(5);
-        final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
-        final PersistableBundle parameters = new PersistableBundle();
-        final IBinder cbBinder = mock(IBinder.class);
-        when(cb.asBinder()).thenReturn(cbBinder);
-
-        mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters);
-
-        verify(mVendorService).openRanging(
-                eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(),
-                eq(parameters));
-        assertThat(mRangingCbCaptor.getValue()).isNotNull();
-
-        when(mUwbInjector.checkUwbRangingPermissionForDataDelivery(any(), any())).thenReturn(false);
-
-        // Ensure the ranging cb is not delivered to the client.
-        final RangingReport rangingReport = new RangingReport.Builder().build();
-        mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport);
-        verify(cb, never()).onRangingResult(sessionHandle, rangingReport);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 75f8a44..378304d 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -52,6 +52,7 @@
 
     private boolean mIsAvailable = true;
     private long mLatency;
+    private int mOffCount;
 
     private int mCapabilities;
     private int[] mSupportedEffects;
@@ -93,6 +94,7 @@
 
         @Override
         public void off() {
+            mOffCount++;
         }
 
         @Override
@@ -308,6 +310,11 @@
         return mExternalControlStates;
     }
 
+    /** Returns the number of times the vibrator was turned off. */
+    public int getOffCount() {
+        return mOffCount;
+    }
+
     /**
      * Return the {@link PrebakedSegment} effect enabled with given id, or {@code null} if
      * missing or disabled.
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/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
index a732bd1..9fb8b38 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
@@ -259,6 +259,21 @@
     }
 
     @Test
+    public void reset_turnsOffVibratorAndDisablesExternalControl() {
+        mockVibratorCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+        when(mNativeWrapperMock.on(anyLong(), anyLong())).thenAnswer(args -> args.getArgument(0));
+        VibratorController controller = createController();
+
+        controller.on(100, 1);
+        assertTrue(controller.isVibrating());
+
+        controller.reset();
+        assertFalse(controller.isVibrating());
+        verify(mNativeWrapperMock).setExternalControl(eq(false));
+        verify(mNativeWrapperMock).off();
+    }
+
+    @Test
     public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
         when(mNativeWrapperMock.on(anyLong(), anyLong())).thenAnswer(args -> args.getArgument(0));
         VibratorController controller = createController();
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 5a00e0d..f9e63d1 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -35,7 +35,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
@@ -95,6 +94,8 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
 /**
@@ -232,6 +233,19 @@
     }
 
     @Test
+    public void createService_resetsVibrators() {
+        mockVibrators(1, 2);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+
+        createService();
+        assertEquals(1, mVibratorProviders.get(1).getOffCount());
+        assertEquals(1, mVibratorProviders.get(2).getOffCount());
+        assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates());
+        assertEquals(Arrays.asList(false), mVibratorProviders.get(2).getExternalControlStates());
+    }
+
+    @Test
     public void createService_doNotCrashIfUsedBeforeSystemReady() {
         mockVibrators(1, 2);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
@@ -696,10 +710,12 @@
                         VibratorManagerService.OnSyncedVibrationCompleteListener.class);
         verify(mNativeWrapperMock).init(listenerCaptor.capture());
 
-        // Mock trigger callback on registered listener.
+        CountDownLatch triggerCountDown = new CountDownLatch(1);
+        // Mock trigger callback on registered listener right after the synced vibration starts.
         when(mNativeWrapperMock.prepareSynced(eq(new int[]{1, 2}))).thenReturn(true);
         when(mNativeWrapperMock.triggerSynced(anyLong())).then(answer -> {
             listenerCaptor.getValue().onComplete(answer.getArgument(0));
+            triggerCountDown.countDown();
             return true;
         });
 
@@ -708,20 +724,19 @@
                 .compose();
         CombinedVibration effect = CombinedVibration.createParallel(composed);
 
-        // Wait for vibration to start, it should finish right away with trigger callback.
         vibrate(service, effect, ALARM_ATTRS);
-
-        // VibrationThread will start this vibration async, so wait until callback is triggered.
-        assertTrue(waitUntil(s -> !listenerCaptor.getAllValues().isEmpty(), service,
-                TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async, so wait until vibration is triggered.
+        triggerCountDown.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
 
         verify(mNativeWrapperMock).prepareSynced(eq(new int[]{1, 2}));
         verify(mNativeWrapperMock).triggerSynced(anyLong());
-
         PrimitiveSegment expected = new PrimitiveSegment(
                 VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 100);
         assertEquals(Arrays.asList(expected), mVibratorProviders.get(1).getEffectSegments());
         assertEquals(Arrays.asList(expected), mVibratorProviders.get(2).getEffectSegments());
+
+        // VibrationThread needs some time to react to native callbacks and stop the vibrator.
+        assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
     }
 
     @Test
@@ -989,7 +1004,7 @@
         mExternalVibratorService.onExternalVibrationStop(externalVibration);
 
         assertEquals(IExternalVibratorService.SCALE_NONE, scale);
-        assertEquals(Arrays.asList(true, false),
+        assertEquals(Arrays.asList(false, true, false),
                 mVibratorProviders.get(1).getExternalControlStates());
     }
 
@@ -1013,9 +1028,10 @@
         assertEquals(IExternalVibratorService.SCALE_NONE, firstScale);
         assertEquals(IExternalVibratorService.SCALE_NONE, secondScale);
         verify(firstController).mute();
-        verifyNoMoreInteractions(secondController);
+        verify(secondController, never()).mute();
         // Set external control called only once.
-        assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates());
+        assertEquals(Arrays.asList(false, true),
+                mVibratorProviders.get(1).getExternalControlStates());
     }
 
     @Test
@@ -1037,7 +1053,8 @@
 
         // Vibration is cancelled.
         assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
-        assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates());
+        assertEquals(Arrays.asList(false, true),
+                mVibratorProviders.get(1).getExternalControlStates());
     }
 
     private VibrationEffectSegment expectedPrebaked(int effectId) {
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
index 78afb7b..fdaf7cc 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
@@ -27,6 +27,13 @@
         <service android:name=".SimpleIsolatedService"
                  android:isolatedProcess="true"
                  android:exported="true" />
+        <receiver android:name=".SimpleReceiver"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.servicestests.apps.simpleservicetestapp.TEST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </receiver>
     </application>
 
 </manifest>
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
index ccfc0b7..56e1ab7 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
@@ -38,6 +38,7 @@
     private static final int MSG_DONE = 1;
     private static final int MSG_START_FOREGROUND = 2;
     private static final int MSG_STOP_FOREGROUND = 3;
+    private static final int MSG_STOP_SERVICE = 4;
 
     private static final String ACTION_FGS_STATS_TEST =
             "com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
@@ -57,6 +58,11 @@
                     stopForeground(true);
                     sendRemoteMessage(MSG_DONE, 0, 0, null);
                 } break;
+                case MSG_STOP_SERVICE: {
+                    Log.i(TAG, "stopSelf");
+                    stopSelf();
+                    sendRemoteMessage(MSG_DONE, 0, 0, null);
+                } break;
             }
         }
     };
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleReceiver.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleReceiver.java
new file mode 100644
index 0000000..1eced84
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleReceiver.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.servicestests.apps.simpleservicetestapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class SimpleReceiver extends BroadcastReceiver {
+    private static final String TAG = SimpleReceiver.class.getSimpleName();
+    private static final String EXTRA_CALLBACK = "callback";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.i(TAG, "onReceive " + intent);
+        final Bundle extra = intent.getExtras();
+        if (extra != null) {
+            final IBinder binder = extra.getBinder(EXTRA_CALLBACK);
+            if (binder != null) {
+                IRemoteCallback callback = IRemoteCallback.Stub.asInterface(binder);
+                try {
+                    callback.sendResult(null);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+    }
+}
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/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
index a67f645..1612321 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
@@ -18,13 +18,14 @@
 
 import android.annotation.NonNull;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
 import android.util.ArrayMap;
 import android.util.Pair;
 
 import com.android.internal.util.Preconditions;
-import com.android.server.utils.DeviceConfigInterface;
 
 import java.lang.reflect.Constructor;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
@@ -33,10 +34,17 @@
 
 public class FakeDeviceConfigInterface implements DeviceConfigInterface {
 
+    private static final String COMPOSITE_DELIMITER = "/";
     private Map<String, String> mProperties = new HashMap<>();
     private ArrayMap<DeviceConfig.OnPropertiesChangedListener, Pair<String, Executor>> mListeners =
             new ArrayMap<>();
 
+    private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
+        Preconditions.checkNotNull(namespace);
+        Preconditions.checkNotNull(name);
+        return namespace + COMPOSITE_DELIMITER + name;
+    }
+
     public void clearProperties() {
         mProperties.clear();
     }
@@ -91,6 +99,59 @@
     }
 
     @Override
+    public DeviceConfig.Properties getProperties(String namespace, String... names) {
+        if (!mProperties.keySet().contains(namespace)) {
+            return new DeviceConfig.Properties(namespace, null);
+        }
+        DeviceConfig.Properties.Builder propertiesBuilder = new DeviceConfig.Properties.Builder(
+                namespace);
+
+        for (String compositeName : mProperties.keySet()) {
+            if (compositeName.split(COMPOSITE_DELIMITER).length != 2) {
+                continue;
+            }
+
+            String existingPropertyNamespace = compositeName.split(COMPOSITE_DELIMITER)[0];
+            String existingPropertyName = compositeName.split(COMPOSITE_DELIMITER)[1];
+
+            if ((names.length == 0 && existingPropertyNamespace.equals(namespace)) || Arrays.asList(
+                    names).contains(compositeName)) {
+                propertiesBuilder.setString(existingPropertyName, mProperties.get(compositeName));
+            }
+        }
+
+        return propertiesBuilder.build();
+    }
+
+    @Override
+    public boolean setProperty(String namespace, String name, String value, boolean makeDefault) {
+        putPropertyAndNotify(namespace, name, value);
+        return true;
+    }
+
+    @Override
+    public boolean setProperties(DeviceConfig.Properties properties)
+            throws DeviceConfig.BadConfigException {
+        for (String property : properties.getKeyset()) {
+            String compositeName = createCompositeName(properties.getNamespace(), property);
+            putPropertyAndNotify(properties.getNamespace(), compositeName,
+                    properties.getString(property, ""));
+        }
+        return true;
+    }
+
+    @Override
+    public boolean deleteProperty(String namespace, String name) {
+        mProperties.remove(createCompositeName(namespace, name));
+        return true;
+    }
+
+    @Override
+    public void resetToDefaults(int resetMode, String namespace) {
+        clearProperties();
+    }
+
+    @Override
     public String getString(String namespace, String name, String defaultValue) {
         String value = getProperty(namespace, name);
         return value != null ? value : defaultValue;
@@ -166,10 +227,4 @@
             DeviceConfig.OnPropertiesChangedListener listener) {
         mListeners.remove(listener);
     }
-
-    private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
-        Preconditions.checkNotNull(namespace);
-        Preconditions.checkNotNull(name);
-        return namespace + "/" + name;
-    }
 }
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 1ba414e..2128a08 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -58,7 +58,6 @@
     jni_libs: [
         "libdexmakerjvmtiagent",
         "libmultiplejvmtiagentsinterferenceagent",
-        "libbacktrace",
         "libbase",
         "libbinder",
         "libc++",
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/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 71c05b5..ea46eab 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -32,6 +32,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
@@ -72,6 +73,7 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Slog;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
@@ -1182,6 +1184,7 @@
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
 
         mService.buzzBeepBlinkLocked(r);
+        verifyDelayedVibrate(mService.getVibratorHelper().createFallbackVibration(false));
 
         // quiet update should stop making noise
         mService.buzzBeepBlinkLocked(s);
@@ -1564,6 +1567,32 @@
     }
 
     @Test
+    public void testRingtoneInsistentBeep_canUpdate() throws Exception {
+        NotificationChannel ringtoneChannel =
+                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
+        ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
+                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
+        ringtoneChannel.enableVibration(true);
+        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
+        mService.addNotification(ringtoneNotification);
+        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+        mService.buzzBeepBlinkLocked(ringtoneNotification);
+        verifyBeepLooped();
+        verifyDelayedVibrateLooped();
+        Mockito.reset(mVibrator);
+        Mockito.reset(mRingtonePlayer);
+
+        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+        mService.buzzBeepBlinkLocked(ringtoneNotification);
+
+        // beep wasn't reset
+        verifyNeverBeep();
+        verifyNeverVibrate();
+        verify(mRingtonePlayer, never()).stopAsync();
+        verify(mVibrator, never()).cancel();
+    }
+
+    @Test
     public void testCannotInterruptRingtoneInsistentBuzz() {
         NotificationChannel ringtoneChannel =
                 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
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 7bbf3e6..f660af0 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -516,7 +516,7 @@
 
         when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
 
-        mWorkerHandler = mService.new WorkerHandler(mTestableLooper.getLooper());
+        mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
         mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
                 mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
                 mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
@@ -2703,6 +2703,42 @@
     }
 
     @Test
+    public void testCrossUserSnooze() {
+        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
+        mService.addNotification(r);
+        NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
+        mService.addNotification(r2);
+
+        mListener = mock(ManagedServices.ManagedServiceInfo.class);
+        mListener.component = new ComponentName(PKG, PKG);
+        when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
+        when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+        mService.snoozeNotificationInt(r.getKey(), 1000, null, mListener);
+
+        verify(mWorkerHandler, never()).post(
+                any(NotificationManagerService.SnoozeNotificationRunnable.class));
+    }
+
+    @Test
+    public void testSameUserSnooze() {
+        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
+        mService.addNotification(r);
+        NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
+        mService.addNotification(r2);
+
+        mListener = mock(ManagedServices.ManagedServiceInfo.class);
+        mListener.component = new ComponentName(PKG, PKG);
+        when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
+        when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+        mService.snoozeNotificationInt(r2.getKey(), 1000, null, mListener);
+
+        verify(mWorkerHandler).post(
+                any(NotificationManagerService.SnoozeNotificationRunnable.class));
+    }
+
+    @Test
     public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception {
         final NotificationRecord notification = generateNotificationRecord(
                 mTestNotificationChannel, 1, null, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index bf0ed71..66d1577 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -91,6 +91,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.service.notification.ConversationChannelWrapper;
@@ -376,27 +377,19 @@
         when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
     }
 
-    private static NotificationChannel createNotificationChannel(String id, String name,
-            int importance) {
-        NotificationChannel channel = new NotificationChannel(id, name, importance);
-        channel.setSound(SOUND_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT);
-        return channel;
-    }
-
     @Test
     public void testWriteXml_onlyBackupsTargetUser() throws Exception {
         // Setup package notifications.
         String package0 = "test.package.user0";
         int uid0 = 1001;
         setUpPackageWithUid(package0, uid0);
-        NotificationChannel channel0 = createNotificationChannel("id0", "name0", IMPORTANCE_HIGH);
+        NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
         assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
 
         String package10 = "test.package.user10";
         int uid10 = 1001001;
         setUpPackageWithUid(package10, uid10);
-        NotificationChannel channel10 = createNotificationChannel("id10", "name10",
-                IMPORTANCE_HIGH);
+        NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH);
         assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10);
@@ -421,7 +414,7 @@
         String package0 = "test.package.user0";
         int uid0 = 1001;
         setUpPackageWithUid(package0, uid0);
-        NotificationChannel channel0 = createNotificationChannel("id0", "name0", IMPORTANCE_HIGH);
+        NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
         assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0);
@@ -514,8 +507,9 @@
         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
         NotificationChannel channel1 =
-                createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
-        NotificationChannel channel2 = createNotificationChannel("id2", "name2", IMPORTANCE_LOW);
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        NotificationChannel channel2 =
+                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel2.setDescription("descriptions for all");
         channel2.setSound(SOUND_URI, mAudioAttributes);
         channel2.enableLights(true);
@@ -524,7 +518,7 @@
         channel2.enableVibration(false);
         channel2.setGroup(ncg.getId());
         channel2.setLightColor(Color.BLUE);
-        NotificationChannel channel3 = createNotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
+        NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
         channel3.enableVibration(true);
 
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
@@ -631,8 +625,7 @@
     }
 
     @Test
-    public void testRestoreXml_withNonExistentCanonicalizedSoundUri_ignoreChannel()
-            throws Exception {
+    public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
         Thread.sleep(3000);
         doReturn(null)
                 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
@@ -650,7 +643,7 @@
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
-        assertNull(actualChannel);
+        assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
     }
 
 
@@ -659,8 +652,7 @@
      * handle its restore properly.
      */
     @Test
-    public void testRestoreXml_withUncanonicalizedNonLocalSoundUri_ignoreChannel()
-            throws Exception {
+    public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
         // Not a local uncanonicalized uri, simulating that it fails to exist locally
         doReturn(null)
                 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
@@ -679,7 +671,7 @@
                 backupWithUncanonicalizedSoundUri.getBytes(), true, UserHandle.USER_SYSTEM);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
-        assertNull(actualChannel);
+        assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
     }
 
     @Test
@@ -703,11 +695,11 @@
         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
         NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
         NotificationChannel channel1 =
-                createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel2 =
-                createNotificationChannel("id2", "name2", IMPORTANCE_HIGH);
+                new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
         NotificationChannel channel3 =
-                createNotificationChannel("id3", "name3", IMPORTANCE_LOW);
+                new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
         channel3.setGroup(ncg.getId());
 
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
@@ -3062,7 +3054,7 @@
     @Test
     public void testChannelXml_backupDefaultApp() throws Exception {
         NotificationChannel channel1 =
-                createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
 
         mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false);
 
@@ -3343,7 +3335,7 @@
                 mAppOpsManager, mStatsEventBuilderFactory);
 
         mHelper.createNotificationChannel(
-                PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false);
+                PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
         assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
         assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
     }
@@ -3354,7 +3346,7 @@
                 mAppOpsManager, mStatsEventBuilderFactory);
 
         mHelper.createNotificationChannel(
-                PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false);
+                PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
         mHelper.deleteNotificationChannel(PKG_P, UID_P, "id");
         NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
         assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 733d3f0..9dca235 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.notification;
 
+import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
+
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertNull;
@@ -36,13 +38,10 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -81,10 +80,12 @@
         ZenModeConfig config = getMutedAllConfig();
         config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
 
+        // Explicitly allow conversations from priority senders to make sure that goes through
         ZenPolicy zenPolicy = new ZenPolicy.Builder()
                 .allowAlarms(true)
                 .allowReminders(true)
                 .allowEvents(true)
+                .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
                 .showLights(false)
                 .showInAmbientDisplay(false)
                 .build();
@@ -93,11 +94,12 @@
         int priorityCategories = originalPolicy.priorityCategories;
         int priorityCallSenders = originalPolicy.priorityCallSenders;
         int priorityMessageSenders = originalPolicy.priorityMessageSenders;
-        int priorityConversationsSenders = originalPolicy.priorityConversationSenders;
+        int priorityConversationsSenders = CONVERSATION_SENDERS_IMPORTANT;
         int suppressedVisualEffects = originalPolicy.suppressedVisualEffects;
         priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
         priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
         priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
         suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
         suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
 
@@ -344,7 +346,7 @@
         config.allowCallsFrom = ZenModeConfig.SOURCE_ANYONE;
         config.allowMessagesFrom = ZenModeConfig.SOURCE_ANYONE;
         config.allowConversations = true;
-        config.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
+        config.allowConversationsFrom = CONVERSATION_SENDERS_IMPORTANT;
 
         config.suppressedVisualEffects = 0;
         return config;
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 222c692..6b36fe8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -69,7 +69,7 @@
 
     @Before
     public void setUp() {
-        mDetector = new SingleKeyGestureDetector(mContext);
+        mDetector = new SingleKeyGestureDetector();
         initSingleKeyGestureRules();
         mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
         mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
@@ -78,7 +78,7 @@
     }
 
     private void initSingleKeyGestureRules() {
-        mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER,
+        mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(mContext, KEYCODE_POWER,
                 KEY_LONGPRESS | KEY_VERYLONGPRESS) {
             @Override
             int getMaxMultiPressCount() {
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 b282cd7..0b91802 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -404,6 +404,7 @@
 
         // Another round without setting visibility of the trampoline activity.
         onActivityLaunchedTrampoline();
+        mTrampolineActivity.setState(ActivityRecord.State.PAUSING, "test");
         notifyWindowsDrawn(mTopActivity);
         // If the transition can start, the invisible activities should be discarded and the launch
         // event be reported successfully.
@@ -475,6 +476,16 @@
     }
 
     @Test
+    public void testConsecutiveLaunch() {
+        mTrampolineActivity.setState(ActivityRecord.State.INITIALIZING, "test");
+        onActivityLaunched(mTrampolineActivity);
+        mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
+                mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
+        notifyActivityLaunched(START_SUCCESS, mTopActivity);
+        transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
+    }
+
+    @Test
     public void testConsecutiveLaunchNewTask() {
         final IBinder launchCookie = mock(IBinder.class);
         final WindowContainerToken launchRootTask = mock(WindowContainerToken.class);
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 41f2246..9ad479a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -40,6 +40,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -147,6 +148,7 @@
 
 import java.util.ArrayList;
 import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 
 /**
@@ -217,7 +219,7 @@
     public void testNoCleanupMovingActivityInSameStack() {
         final ActivityRecord activity = createActivityWith2LevelTask();
         final Task rootTask = activity.getRootTask();
-        final Task newTask = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask).build();
+        final Task newTask = createTaskInRootTask(rootTask, 0 /* userId */);
         activity.reparent(newTask, 0, null /*reason*/);
         verify(rootTask, times(0)).cleanUpActivityReferences(any());
     }
@@ -1603,16 +1605,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
@@ -2501,8 +2510,10 @@
     @Test
     public void testTransferStartingWindow() {
         registerTestStartingWindowOrganizer();
-        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
-        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setVisible(false).build();
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setVisible(false).build();
         activity1.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                 false, false);
@@ -2511,6 +2522,7 @@
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
                 true, true, false, true, false, false);
         waitUntilHandlersIdle();
+        assertFalse(mDisplayContent.mSkipAppTransitionAnimation);
         assertNoStartingWindow(activity1);
         assertHasStartingWindow(activity2);
     }
@@ -2618,6 +2630,7 @@
                 false /* newTask */, false /* isTaskSwitch */, null /* options */,
                 null /* sourceRecord */);
 
+        assertTrue(mDisplayContent.mSkipAppTransitionAnimation);
         assertNull(middle.mStartingWindow);
         assertHasStartingWindow(top);
         assertTrue(top.isVisible());
@@ -2899,6 +2912,73 @@
         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
     }
 
+    @Test
+    public void testImeInsetsFrozenFlag_resetWhenReparented() {
+        final ActivityRecord activity = createActivityWithTask();
+        final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app");
+        final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+        final Task newTask = new TaskBuilder(mSupervisor).build();
+        makeWindowVisible(app, imeWindow);
+        mDisplayContent.mInputMethodWindow = imeWindow;
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+
+        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+        activity.setState(RESUMED, "test");
+        activity.reparent(newTask, 0 /* top */, "test");
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+    }
+
+    @UseTestDisplay(addWindows = W_INPUT_METHOD)
+    @Test
+    public void testImeInsetsFrozenFlag_resetWhenResized() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        makeWindowVisibleAndDrawn(app, mImeWindow);
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+
+        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+        app.mActivityRecord.onResize();
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+    }
+
+    @UseTestDisplay(addWindows = W_INPUT_METHOD)
+    @Test
+    public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        makeWindowVisibleAndDrawn(app, mImeWindow);
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+
+        // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        app.mActivityRecord.commitVisibility(false, false);
+        app.mActivityRecord.onWindowsGone();
+
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Expect IME insets frozen state will reset when the activity has no IME focusable window.
+        app.mActivityRecord.forAllWindowsUnchecked(w -> {
+            w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+            return true;
+        }, true);
+
+        app.mActivityRecord.commitVisibility(true, false);
+        app.mActivityRecord.onWindowsVisible();
+
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+    }
+
     private void assertHasStartingWindow(ActivityRecord atoken) {
         assertNotNull(atoken.mStartingSurface);
         assertNotNull(atoken.mStartingData);
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 1b4d0a4..3e8a2e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -478,7 +478,7 @@
         final ActivityRecord splitSecondActivity =
                 new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord splitPrimaryActivity = new TaskBuilder(mSupervisor)
-                .setParentTask(splitOrg.mPrimary)
+                .setParentTaskFragment(splitOrg.mPrimary)
                 .setCreateActivity(true)
                 .build()
                 .getTopMostActivity();
@@ -856,7 +856,7 @@
         // Create another activity on top of the secondary display.
         final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
+        final Task topTask = new TaskBuilder(mSupervisor).setParentTaskFragment(topStack).build();
         new ActivityBuilder(mAtm).setTask(topTask).build();
 
         doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger();
@@ -920,7 +920,7 @@
                 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
         final Task task = new TaskBuilder(mSupervisor)
                 .setComponent(componentName)
-                .setParentTask(stack)
+                .setParentTaskFragment(stack)
                 .build();
         return new ActivityBuilder(mAtm)
                 .setComponent(componentName)
@@ -1056,8 +1056,8 @@
         final ActivityStarter starter = prepareStarter(0 /* flags */);
         starter.mStartActivity = new ActivityBuilder(mAtm).build();
         final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
-                .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
-                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
+                .setParentTaskFragment(createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
+                        ACTIVITY_TYPE_STANDARD))
                 .setUserId(10)
                 .build();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 8ca14bc..b95d56b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -173,7 +173,10 @@
             @Override
             public void onFixedRotationFinished(int displayId) {}
         };
-        mAtm.mWindowManager.registerDisplayWindowListener(listener);
+        int[] displayIds = mAtm.mWindowManager.registerDisplayWindowListener(listener);
+        for (int i = 0; i < displayIds.length; i++) {
+            added.add(displayIds[i]);
+        }
         // Check that existing displays call added
         assertEquals(mRootWindowContainer.getChildCount(), added.size());
         assertEquals(0, changed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 0d177c1..a34586b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -30,6 +30,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;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -40,8 +41,10 @@
 
 import android.app.WaitResult;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.ConditionVariable;
+import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
 
@@ -49,6 +52,7 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
 
 import java.util.concurrent.TimeUnit;
 
@@ -108,16 +112,18 @@
         final ActivityMetricsLogger.LaunchingState launchingState =
                 new ActivityMetricsLogger.LaunchingState();
         spyOn(launchingState);
-        doReturn(true).when(launchingState).contains(eq(secondActivity));
+        doReturn(true).when(launchingState).hasActiveTransitionInfo();
+        doReturn(true).when(launchingState).contains(
+                ArgumentMatchers.argThat(r -> r == firstActivity || r == secondActivity));
         // The test case already runs inside global lock, so above thread can only execute after
         // this waiting method that releases the lock.
         mSupervisor.waitActivityVisibleOrLaunched(taskToFrontWait, firstActivity, launchingState);
 
         // Assert that the thread is finished.
         assertTrue(condition.block(TIMEOUT_MS));
-        assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT);
-        assertEquals(taskToFrontWait.who, secondActivity.mActivityComponent);
-        assertEquals(taskToFrontWait.launchState, WaitResult.LAUNCH_STATE_HOT);
+        assertEquals(START_TASK_TO_FRONT, taskToFrontWait.result);
+        assertEquals(secondActivity.mActivityComponent, taskToFrontWait.who);
+        assertEquals(WaitResult.LAUNCH_STATE_HOT, taskToFrontWait.launchState);
         // START_TASK_TO_FRONT means that another component will be visible, so the component
         // should not be assigned as the first activity.
         assertNull(launchedComponent[0]);
@@ -187,6 +193,24 @@
         verify(taskChangeNotifier, never()).notifyActivityDismissingDockedRootTask();
     }
 
+    /** Ensures that the calling package name passed to client complies with package visibility. */
+    @Test
+    public void testFilteredReferred() {
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setLaunchedFromPackage("other.package").setCreateTask(true).build();
+        assertNotNull(activity.launchedFromPackage);
+        try {
+            mSupervisor.realStartActivityLocked(activity, activity.app, false /* andResume */,
+                    false /* checkConfig */);
+        } catch (RemoteException ignored) {
+        }
+        verify(activity).getFilteredReferrer(eq(activity.launchedFromPackage));
+
+        activity.deliverNewIntentLocked(ActivityBuilder.DEFAULT_FAKE_UID,
+                new Intent(), null /* intentGrants */, "other.package2");
+        verify(activity).getFilteredReferrer(eq("other.package2"));
+    }
+
     /**
      * Ensures that notify focus task changes.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 3a6aac9..53bae41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -26,15 +26,19 @@
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.verify;
 
 import android.os.Binder;
 import android.os.IBinder;
@@ -47,8 +51,9 @@
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
 import android.view.WindowManager;
+import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizer;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
@@ -94,11 +99,10 @@
         assertEquals(WindowManager.TRANSIT_OLD_UNSET,
                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null, null, false));
+                        mDisplayContent.mChangingContainers, null, null, false));
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testTranslucentOpen() {
         final ActivityRecord behind = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -112,12 +116,11 @@
 
         assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN,
                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
-                    mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                    null, null, false));
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null, null, false));
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testTranslucentClose() {
         final ActivityRecord behind = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -129,11 +132,10 @@
         assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE,
                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null, null, false));
+                        mDisplayContent.mChangingContainers, null, null, false));
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testChangeIsNotOverwritten() {
         final ActivityRecord behind = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -144,14 +146,14 @@
         mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
         mDisplayContent.mOpeningApps.add(behind);
         mDisplayContent.mOpeningApps.add(translucentOpening);
+        mDisplayContent.mChangingContainers.add(translucentOpening.getTask());
         assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null, null, false));
+                        mDisplayContent.mChangingContainers, null, null, false));
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testTransitWithinTask() {
         final ActivityRecord opening = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
@@ -198,7 +200,7 @@
         assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN,
                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        appWindowClosing, null, false));
+                        mDisplayContent.mChangingContainers, appWindowClosing, null, false));
     }
 
     @Test
@@ -229,7 +231,7 @@
         assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN,
                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        appWindowClosing, null, false));
+                        mDisplayContent.mChangingContainers, appWindowClosing, null, false));
     }
 
     @Test
@@ -375,7 +377,7 @@
         final ArraySet<ActivityRecord> closing = new ArraySet<>();
         closing.add(activity3);
 
-        // Promote animation targets to TaskStack level. Invisible ActivityRecords don't affect
+        // Promote animation targets to root Task level. Invisible ActivityRecords don't affect
         // promotion decision.
         assertEquals(
                 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
@@ -520,6 +522,128 @@
                         opening, closing, false /* visible */));
     }
 
+    @Test
+    public void testGetAnimationTargets_openingClosingTaskFragment() {
+        // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible)
+        //                        +- [TaskFragment2] - [ActivityRecord2] (closing, visible)
+        final Task parentTask = createTask(mDisplayContent);
+        final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(parentTask,
+                false /* createEmbeddedTask */);
+        final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+        activity1.setVisible(false);
+        activity1.mVisibleRequested = true;
+
+        final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(parentTask,
+                false /* createEmbeddedTask */);
+        final ActivityRecord activity2 = taskFragment2.getTopMostActivity();
+        activity2.setVisible(true);
+        activity2.mVisibleRequested = false;
+
+        final ArraySet<ActivityRecord> opening = new ArraySet<>();
+        opening.add(activity1);
+        final ArraySet<ActivityRecord> closing = new ArraySet<>();
+        closing.add(activity2);
+
+        // Promote animation targets up to TaskFragment level, not beyond.
+        assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, true /* visible */));
+        assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, false /* visible */));
+    }
+
+    @Test
+    public void testGetAnimationTargets_openingClosingTaskFragmentWithEmbeddedTask() {
+        // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible)
+        //                        +- [TaskFragment2] - [ActivityRecord2] (closing, visible)
+        final Task parentTask = createTask(mDisplayContent);
+        final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(parentTask,
+                true /* createEmbeddedTask */);
+        final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+        activity1.setVisible(false);
+        activity1.mVisibleRequested = true;
+
+        final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(parentTask,
+                true /* createEmbeddedTask */);
+        final ActivityRecord activity2 = taskFragment2.getTopMostActivity();
+        activity2.setVisible(true);
+        activity2.mVisibleRequested = false;
+
+        final ArraySet<ActivityRecord> opening = new ArraySet<>();
+        opening.add(activity1);
+        final ArraySet<ActivityRecord> closing = new ArraySet<>();
+        closing.add(activity2);
+
+        // Promote animation targets up to TaskFragment level, not beyond.
+        assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, true /* visible */));
+        assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, false /* visible */));
+    }
+
+    @Test
+    public void testGetAnimationTargets_openingTheOnlyTaskFragmentInTask() {
+        // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (opening, invisible)
+        //               +- [Task2] - [ActivityRecord2] (closing, visible)
+        final Task task1 = createTask(mDisplayContent);
+        final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task1,
+                false /* createEmbeddedTask */);
+        final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+        activity1.setVisible(false);
+        activity1.mVisibleRequested = true;
+
+        final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
+        activity2.setVisible(true);
+        activity2.mVisibleRequested = false;
+
+        final ArraySet<ActivityRecord> opening = new ArraySet<>();
+        opening.add(activity1);
+        final ArraySet<ActivityRecord> closing = new ArraySet<>();
+        closing.add(activity2);
+
+        // Promote animation targets up to leaf Task level because there's only one TaskFragment in
+        // the Task.
+        assertEquals(new ArraySet<>(new WindowContainer[]{task1}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, true /* visible */));
+        assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, false /* visible */));
+    }
+
+    @Test
+    public void testGetAnimationTargets_closingTheOnlyTaskFragmentInTask() {
+        // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (closing, visible)
+        //               +- [Task2] - [ActivityRecord2] (opening, invisible)
+        final Task task1 = createTask(mDisplayContent);
+        final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task1,
+                false /* createEmbeddedTask */);
+        final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+        activity1.setVisible(true);
+        activity1.mVisibleRequested = false;
+
+        final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
+        activity2.setVisible(false);
+        activity2.mVisibleRequested = true;
+
+        final ArraySet<ActivityRecord> opening = new ArraySet<>();
+        opening.add(activity2);
+        final ArraySet<ActivityRecord> closing = new ArraySet<>();
+        closing.add(activity1);
+
+        // Promote animation targets up to leaf Task level because there's only one TaskFragment in
+        // the Task.
+        assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, true /* visible */));
+        assertEquals(new ArraySet<>(new WindowContainer[]{task1}),
+                AppTransitionController.getAnimationTargets(
+                        opening, closing, false /* visible */));
+    }
+
     static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
         @Override
         public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
@@ -619,4 +743,38 @@
                 mAppTransitionController.getRemoteAnimationOverride(
                         activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
     }
+
+    @Test
+    public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() {
+        // TaskFragmentOrganizer registers remote animation.
+        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+        final ITaskFragmentOrganizer iOrganizer =
+                ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
+        final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+                new TestRemoteAnimationRunner(), 10, 1);
+        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
+        mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
+        mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
+
+        // Create a TaskFragment with embedded activity.
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(createTask(mDisplayContent))
+                .createActivityCount(1)
+                .setOrganizer(organizer)
+                .build();
+        final ActivityRecord activity = taskFragment.getTopMostActivity();
+        activity.allDrawn = true;
+        spyOn(mDisplayContent.mAppTransition);
+
+        // Prepare a transition for TaskFragment.
+        mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0);
+        mDisplayContent.mOpeningApps.add(activity);
+        mDisplayContent.mChangingContainers.add(taskFragment);
+        mDisplayContent.mAppTransitionController.handleAppTransitionReady();
+
+        // Check if the transition has been overridden.
+        verify(mDisplayContent.mAppTransition)
+                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+    }
 }
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index c3279bf..a0a3ce7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -18,11 +18,16 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
 import static android.view.WindowManager.TRANSIT_OPEN;
 
@@ -30,6 +35,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.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -37,9 +43,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
 import android.view.Display;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
@@ -82,8 +90,8 @@
         assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null /* wallpaperTarget */, null /* oldWallpaper */,
-                        false /*skipAppTransitionAnimation*/));
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
     }
 
     @Test
@@ -97,8 +105,8 @@
         assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null /* wallpaperTarget */, null /* oldWallpaper */,
-                        false /*skipAppTransitionAnimation*/));
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
     }
 
     @Test
@@ -112,8 +120,8 @@
         assertEquals(TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE,
                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null /* wallpaperTarget */, null /* oldWallpaper */,
-                        false /*skipAppTransitionAnimation*/));
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
     }
 
     @Test
@@ -127,8 +135,8 @@
         assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null /* wallpaperTarget */, null /* oldWallpaper */,
-                        false /*skipAppTransitionAnimation*/));
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
     }
 
     @Test
@@ -142,8 +150,129 @@
         assertEquals(TRANSIT_OLD_UNSET,
                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                        null /* wallpaperTarget */, null /* oldWallpaper */,
-                        true /*skipAppTransitionAnimation*/));
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, true /*skipAppTransitionAnimation*/));
+    }
+
+    @Test
+    public void testTaskChangeWindowingMode() {
+        final ActivityRecord activity = createActivityRecord(mDc);
+
+        mDc.prepareAppTransition(TRANSIT_OPEN);
+        mDc.prepareAppTransition(TRANSIT_CHANGE);
+        mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority
+        mDc.mChangingContainers.add(activity.getTask());
+
+        assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
+                AppTransitionController.getTransitCompatType(mDc.mAppTransition,
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
+    }
+
+    @Test
+    public void testTaskFragmentChange() {
+        final ActivityRecord activity = createActivityRecord(mDc);
+        final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(),
+                true /* createdByOrganizer */, true /* isEmbedded */);
+        activity.getTask().addChild(taskFragment, POSITION_TOP);
+        activity.reparent(taskFragment, POSITION_TOP);
+
+        mDc.prepareAppTransition(TRANSIT_OPEN);
+        mDc.prepareAppTransition(TRANSIT_CHANGE);
+        mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority
+        mDc.mChangingContainers.add(taskFragment);
+
+        assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CHANGE,
+                AppTransitionController.getTransitCompatType(mDc.mAppTransition,
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
+    }
+
+    @Test
+    public void testTaskFragmentOpeningTransition() {
+        final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+                false /* createEmbeddedTask */);
+        activity.setVisible(false);
+
+        mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
+        mDisplayContent.mOpeningApps.add(activity);
+        assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN,
+                AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /* skipAppTransitionAnimation */));
+    }
+
+    @Test
+    public void testEmbeddedTaskOpeningTransition() {
+        final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+                true /* createEmbeddedTask */);
+        activity.setVisible(false);
+
+        mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
+        mDisplayContent.mOpeningApps.add(activity);
+        assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN,
+                AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /* skipAppTransitionAnimation */));
+    }
+
+    @Test
+    public void testTaskFragmentClosingTransition() {
+        final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+                false /* createEmbeddedTask */);
+        activity.setVisible(true);
+
+        mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+        mDisplayContent.mClosingApps.add(activity);
+        assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
+                AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /* skipAppTransitionAnimation */));
+    }
+
+    @Test
+    public void testEmbeddedTaskClosingTransition() {
+        final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+                true /* createEmbeddedTask */);
+        activity.setVisible(true);
+
+        mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+        mDisplayContent.mClosingApps.add(activity);
+        assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
+                AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+                        mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+                        mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
+                        null /* oldWallpaper */, false /* skipAppTransitionAnimation */));
+    }
+
+    /**
+     * Creates a {@link Task} with two {@link TaskFragment TaskFragments}.
+     * The bottom TaskFragment is to prevent
+     * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) the animation
+     * target} to promote to Task or above.
+     *
+     * @param createEmbeddedTask {@code true} to create embedded Task for verified TaskFragment
+     * @return The Activity to be put in either opening or closing Activity
+     */
+    private ActivityRecord createHierarchyForTaskFragmentTest(boolean createEmbeddedTask) {
+        final Task parentTask = createTask(mDisplayContent);
+        final TaskFragment bottomTaskFragment = createTaskFragmentWithParentTask(parentTask,
+                false /* createEmbeddedTask */);
+        final ActivityRecord bottomActivity = bottomTaskFragment.getTopMostActivity();
+        bottomActivity.setOccludesParent(true);
+        bottomActivity.setVisible(true);
+
+        final TaskFragment verifiedTaskFragment = createTaskFragmentWithParentTask(parentTask,
+                createEmbeddedTask);
+        final ActivityRecord activity = verifiedTaskFragment.getTopMostActivity();
+        activity.setOccludesParent(true);
+
+        return activity;
     }
 
     @Test
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 d086474..4ee0c60 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -25,6 +25,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
 import static android.os.Build.VERSION_CODES.P;
 import static android.os.Build.VERSION_CODES.Q;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -67,6 +68,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;
@@ -107,9 +109,13 @@
 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.hardware.display.VirtualDisplay;
 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;
@@ -135,6 +141,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.utils.WmDisplayCutout;
 
@@ -142,6 +149,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;
@@ -1301,7 +1310,7 @@
     }
 
     @UseTestDisplay(addWindows = { W_ACTIVITY, W_WALLPAPER, W_STATUS_BAR, W_NAVIGATION_BAR,
-            W_NOTIFICATION_SHADE })
+            W_INPUT_METHOD, W_NOTIFICATION_SHADE })
     @Test
     public void testApplyTopFixedRotationTransform() {
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
@@ -1405,6 +1414,14 @@
         assertEquals("The process should receive rotated configuration for compatibility",
                 expectedProcConfig, app2.app.getConfiguration());
 
+        // If the rotated activity requests to show IME, the IME window should use the
+        // transformation from activity to lay out in the same orientation.
+        mDisplayContent.setImeLayeringTarget(mAppWindow);
+        LocalServices.getService(WindowManagerInternal.class).onToggleImeRequested(true /* show */,
+                app.token, app.token, mDisplayContent.mDisplayId);
+        assertTrue(mImeWindow.mToken.hasFixedRotationTransform());
+        assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
+
         // The fixed rotation transform can only be finished when all animation finished.
         doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
         mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
@@ -2220,6 +2237,184 @@
         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, surfaceSize);
+
+        // 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();
+    }
+
+    @Test
+    public void testVirtualDisplayContent_withoutSurface() {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(SurfaceControl.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        setUpDefaultTaskDisplayAreaWindowToken();
+
+        // GIVEN SurfaceControl can successfully mirror the provided surface.
+        Point surfaceSize = new Point(
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+        surfaceControlMirrors(surfaceSize);
+
+        // GIVEN a new VirtualDisplay with an associated surface.
+        final VirtualDisplay display = createVirtualDisplay(surfaceSize, null /* surface */);
+        final int displayId = display.getDisplay().getDisplayId();
+        mWm.mRoot.onDisplayAdded(displayId);
+
+        // WHEN getting the DisplayContent for the new virtual display.
+        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
+
+        // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
+        assertThat(actualDC.mTokenToMirror).isNull();
+
+        display.release();
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testVirtualDisplayContent_withSurface() {
+        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);
+
+        // GIVEN a new VirtualDisplay with an associated surface.
+        final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface());
+        final int displayId = display.getDisplay().getDisplayId();
+        mWm.mRoot.onDisplayAdded(displayId);
+
+        // WHEN getting the DisplayContent for the new virtual display.
+        DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
+
+        // THEN mirroring is initiated for the default display's DisplayArea.
+        assertThat(actualDC.mTokenToMirror).isEqualTo(tokenToMirror);
+
+        display.release();
+        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 VirtualDisplay createVirtualDisplay(Point size, Surface surface) {
+        return mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", size.x, size.y,
+                DisplayMetrics.DENSITY_140, surface, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
+    }
+
     private void removeRootTaskTests(Runnable runnable) {
         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
@@ -2230,10 +2425,10 @@
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
         final Task rootTask4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask1).build();
-        final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask2).build();
-        final Task task3 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask3).build();
-        final Task task4 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask4).build();
+        final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask1).build();
+        final Task task2 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask2).build();
+        final Task task3 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask3).build();
+        final Task task4 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask4).build();
 
         // Reordering root tasks while removing root tasks.
         doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 7cb7c79d..8a6db2c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -117,7 +117,7 @@
         Task rootTask = mTestDisplay.getDefaultTaskDisplayArea()
                 .createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
         mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT)
-                .setParentTask(rootTask).build();
+                .setParentTaskFragment(rootTask).build();
         mTestTask.mUserId = TEST_USER_ID;
         mTestTask.mLastNonFullscreenBounds = TEST_BOUNDS;
         mTestTask.setHasBeenVisible(true);
@@ -353,7 +353,7 @@
         final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
                 .setComponent(ALTERNATIVE_COMPONENT)
                 .setUserId(TEST_USER_ID)
-                .setParentTask(stack)
+                .setParentTaskFragment(stack)
                 .build();
         anotherTaskOfTheSameUser.setWindowingMode(WINDOWING_MODE_FREEFORM);
         anotherTaskOfTheSameUser.setBounds(200, 300, 400, 500);
@@ -365,7 +365,7 @@
         final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
                 .setComponent(TEST_COMPONENT)
                 .setUserId(ALTERNATIVE_USER_ID)
-                .setParentTask(stack)
+                .setParentTaskFragment(stack)
                 .build();
         anotherTaskOfDifferentUser.setWindowingMode(WINDOWING_MODE_FREEFORM);
         anotherTaskOfDifferentUser.setBounds(300, 400, 500, 600);
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 1b078b7..22e687a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -331,7 +331,7 @@
         // other task
         Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setParentTask(mTaskContainer.getRootHomeTask()).build();
+                .setParentTaskFragment(mTaskContainer.getRootHomeTask()).build();
         Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
                 .build();
@@ -471,8 +471,8 @@
         final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build();
         root.mCreatedByOrganizer = true;
         // Add organized and non-organized child.
-        final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build();
-        final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build();
+        final Task child1 = createTaskBuilder(".Task1").setParentTaskFragment(root).build();
+        final Task child2 = createTaskBuilder(".Task2").setParentTaskFragment(root).build();
         doReturn(true).when(child1).isOrganized();
         doReturn(false).when(child2).isOrganized();
         mRecentTasks.add(root);
@@ -508,7 +508,8 @@
         // tasks because their intents are identical.
         mRecentTasks.add(task1);
         // Go home to trigger the removal of untracked tasks.
-        mRecentTasks.add(createTaskBuilder(".Home").setParentTask(mTaskContainer.getRootHomeTask())
+        mRecentTasks.add(createTaskBuilder(".Home")
+                .setParentTaskFragment(mTaskContainer.getRootHomeTask())
                 .build());
         triggerIdleToTrim();
 
@@ -675,7 +676,7 @@
     public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
         // Create some set of tasks, some of which are visible and some are not
         Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
-                .setParentTask(mTaskContainer.getRootHomeTask())
+                .setParentTaskFragment(mTaskContainer.getRootHomeTask())
                 .build();
         homeTask.mUserSetupComplete = true;
         mRecentTasks.add(homeTask);
@@ -696,7 +697,7 @@
         t1.mUserSetupComplete = true;
         mRecentTasks.add(t1);
         Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
-                .setParentTask(mTaskContainer.getRootHomeTask())
+                .setParentTaskFragment(mTaskContainer.getRootHomeTask())
                 .build();
         homeTask.mUserSetupComplete = true;
         mRecentTasks.add(homeTask);
@@ -949,10 +950,10 @@
 
         // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
         // the tasks belong in stacks above the home stack
-        mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
-        mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(aboveHomeStack).build());
-        mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
-        mRecentTasks.add(createTaskBuilder(".Task3").setParentTask(aboveHomeStack).build());
+        mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeStack).build());
+        mRecentTasks.add(createTaskBuilder(".Task1").setParentTaskFragment(aboveHomeStack).build());
+        mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(aboveHomeStack).build());
+        mRecentTasks.add(createTaskBuilder(".Task3").setParentTaskFragment(aboveHomeStack).build());
 
         triggerTrimAndAssertNoTasksTrimmed();
     }
@@ -970,11 +971,11 @@
         // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
         // the home stack is trimmed once a new task is added
         final Task behindHomeTask = createTaskBuilder(".Task1")
-                .setParentTask(behindHomeStack)
+                .setParentTaskFragment(behindHomeStack)
                 .build();
         mRecentTasks.add(behindHomeTask);
-        mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
-        mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
+        mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeStack).build());
+        mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(aboveHomeStack).build());
 
         triggerTrimAndAssertTrimmed(behindHomeTask);
     }
@@ -990,10 +991,12 @@
 
         // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
         // removed
-        mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeTask).build());
-        mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayRootTask).build());
-        mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayRootTask).build());
-        mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeTask).build());
+        mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeTask).build());
+        mRecentTasks.add(createTaskBuilder(".Task1").setParentTaskFragment(otherDisplayRootTask)
+                .build());
+        mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(otherDisplayRootTask)
+                .build());
+        mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTaskFragment(homeTask).build());
 
         triggerTrimAndAssertNoTasksTrimmed();
     }
@@ -1023,7 +1026,7 @@
         Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
         mRecentTasks.add(t1);
         mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".HomeTask")
-                .setParentTask(mTaskContainer.getRootHomeTask()).build());
+                .setParentTaskFragment(mTaskContainer.getRootHomeTask()).build());
         Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
         mRecentTasks.add(t2);
         mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".PipTask")
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index b6cfa8e..89ae5ed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -51,6 +51,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.IInterface;
+import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
@@ -274,6 +275,32 @@
     }
 
     @Test
+    public void testOpeningTaskWithTopFinishingActivity() {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "win");
+        final Task task = win.getTask();
+        final ActivityRecord topFinishing = new ActivityBuilder(mAtm).setTask(task).build();
+        // Now the task contains:
+        //     - Activity[1] (top, finishing, no window)
+        //     - Activity[0] (has window)
+        topFinishing.finishing = true;
+        spyOn(mDisplayContent.mAppTransition);
+        doReturn(mController).when(mDisplayContent.mAppTransition).getRemoteAnimationController();
+        task.applyAnimationUnchecked(null /* lp */, true /* enter */, TRANSIT_OLD_TASK_OPEN,
+                false /* isVoiceInteraction */, null /* sources */);
+        mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        try {
+            verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+                    appsCaptor.capture(), any(), any(), any());
+        } catch (RemoteException ignored) {
+        }
+        assertEquals(1, appsCaptor.getValue().length);
+        assertEquals(RemoteAnimationTarget.MODE_OPENING, appsCaptor.getValue()[0].mode);
+    }
+
+    @Test
     public void testChangeToSmallerSize() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         mDisplayContent.mChangingContainers.add(win.mActivityRecord);
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..030733b 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());
 
@@ -330,7 +329,7 @@
 
         // Create primary splitscreen root task.
         final Task primarySplitScreen = new TaskBuilder(mAtm.mTaskSupervisor)
-                .setParentTask(organizer.mPrimary)
+                .setParentTaskFragment(organizer.mPrimary)
                 .setOnTop(true)
                 .build();
 
@@ -506,8 +505,8 @@
                 targetActivity);
         final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
                 aliasActivity);
-        final Task parentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
-        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(parentTask).build();
+        final Task parentTask = new TaskBuilder(mSupervisor).build();
+        final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(parentTask).build();
         task.origActivity = alias;
         task.realActivity = target;
         new ActivityBuilder(mAtm).setComponent(target).setTask(task).setTargetActivity(
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 8d4acbb..4069f0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -168,7 +168,7 @@
     @Test
     public void testTaskLayerRank() {
         final Task rootTask = new TaskBuilder(mSupervisor).build();
-        final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+        final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
         new ActivityBuilder(mAtm).setTask(task1).build().mVisibleRequested = true;
         mWm.mRoot.rankTaskLayers();
 
@@ -523,7 +523,8 @@
         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */);
-        final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetRootTask).build();
+        final Task targetTask = new TaskBuilder(mSupervisor).setParentTaskFragment(targetRootTask)
+                .build();
 
         // Create Recents on secondary display.
         final TestDisplayContent secondDisplay = addNewDisplayContentAt(
@@ -1007,33 +1008,31 @@
 
     @Test
     public void testLockAllProfileTasks() {
-        // Make an activity visible with the user id set to 0
-        final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
-        final int taskId = task.mTaskId;
-        final ActivityRecord activity = task.getTopMostActivity();
+        final int profileUid = UserHandle.PER_USER_RANGE + UserHandle.MIN_SECONDARY_USER_ID;
+        final int profileUserId = UserHandle.getUserId(profileUid);
+        // Create an activity belonging to the profile user.
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setUid(profileUid).build();
+        final Task task = activity.getTask();
 
-        // Create another activity on top and the user id is 1
-        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task)
-                .setUid(UserHandle.PER_USER_RANGE + 1).build();
-        doReturn(true).when(topActivity).okToShowLocked();
+        // Create another activity belonging to current user on top.
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
         topActivity.intent.setAction(Intent.ACTION_MAIN);
 
         // Make sure the listeners will be notified for putting the task to locked state
         TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController();
         spyOn(controller);
-        mWm.mRoot.lockAllProfileTasks(0);
-        verify(controller).notifyTaskProfileLocked(eq(taskId), eq(0));
+        mWm.mRoot.lockAllProfileTasks(profileUserId);
+        verify(controller).notifyTaskProfileLocked(eq(task.mTaskId), eq(profileUserId));
 
         // Create the work lock activity on top of the task
-        final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task)
-                .setUid(UserHandle.PER_USER_RANGE + 1).build();
-        doReturn(true).when(workLockActivity).okToShowLocked();
+        final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task).build();
         workLockActivity.intent.setAction(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
         doReturn(workLockActivity.mActivityComponent).when(mAtm).getSysUiServiceComponentLocked();
 
         // Make sure the listener won't be notified again.
         clearInvocations(controller);
-        mWm.mRoot.lockAllProfileTasks(0);
+        mWm.mRoot.lockAllProfileTasks(profileUserId);
         verify(controller, never()).notifyTaskProfileLocked(anyInt(), anyInt());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index c44c22f..cb85884 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -166,7 +166,7 @@
         final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
                 .setComponent(new ComponentName(mContext.getPackageName(), className))
                 .setTaskId(taskId)
-                .setParentTask(stack)
+                .setParentTaskFragment(stack)
                 .build();
         task.lastActiveTime = lastActiveTime;
         final ActivityRecord activity = new ActivityBuilder(mAtm)
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 3bebf6b..6407c92 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -40,6 +40,11 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityRecord.State.STOPPED;
@@ -55,7 +60,9 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doCallRealMethod;
 
@@ -101,10 +108,14 @@
 
     private Task mTask;
     private ActivityRecord mActivity;
+    private ActivityMetricsLogger mActivityMetricsLogger;
     private Properties mInitialConstrainDisplayApisFlags;
 
     @Before
     public void setUp() throws Exception {
+        mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
+        clearInvocations(mActivityMetricsLogger);
+        doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger();
         mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties(
                 NAMESPACE_CONSTRAIN_DISPLAY_APIS);
         DeviceConfig.setProperties(
@@ -1939,13 +1950,19 @@
         setUpDisplaySizeWithApp(1000, 2500);
 
         assertFalse(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
 
         prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
         assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
         assertTrue(mActivity.areBoundsLetterboxed());
 
+        verifyLogAppCompatState(mActivity,
+                APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
+
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+        verifyLogAppCompatState(mActivity,
+                APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE);
         rotateDisplay(mActivity.mDisplayContent, ROTATION_0);
 
         // After returning to the original rotation, bounds are computed in
@@ -1955,6 +1972,18 @@
         assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
         assertTrue(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity,
+                APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
+
+        // After setting the visibility of the activity to false, areBoundsLetterboxed() still
+        // returns true but the NOT_VISIBLE App Compat state is logged.
+        mActivity.setVisibility(false);
+        assertTrue(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE);
+        mActivity.setVisibility(true);
+        assertTrue(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity,
+                APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
     }
 
     @Test
@@ -1963,12 +1992,15 @@
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         assertFalse(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
 
         prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
 
         assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
         assertTrue(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity,
+                APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION);
     }
 
     @Test
@@ -1978,12 +2010,15 @@
         prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
 
         assertFalse(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
 
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
 
         assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertTrue(mActivity.inSizeCompatMode());
         assertTrue(mActivity.areBoundsLetterboxed());
+        verifyLogAppCompatState(mActivity,
+                APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE);
     }
 
     /**
@@ -2197,6 +2232,11 @@
                 .isEqualTo(activity.getWindowConfiguration().getBounds());
     }
 
+    private void verifyLogAppCompatState(ActivityRecord activity, int state) {
+        verify(mActivityMetricsLogger, atLeastOnce()).logAppCompatState(
+                argThat(r -> activity == r && r.getAppCompatState() == state));
+    }
+
     static Configuration rotateDisplay(DisplayContent display, int rotation) {
         final Configuration c = new Configuration();
         display.getDisplayRotation().setRotation(rotation);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a8e1753..5bc45d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -258,6 +258,7 @@
         final ActivityManagerInternal amInternal = mAmService.mInternal;
         spyOn(amInternal);
         doNothing().when(amInternal).trimApplications();
+        doNothing().when(amInternal).scheduleAppGcs();
         doNothing().when(amInternal).updateCpuStats();
         doNothing().when(amInternal).updateOomAdj();
         doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
@@ -270,7 +271,6 @@
         doNothing().when(amInternal).cleanUpServices(anyInt(), any(), any());
         doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId();
         doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds();
-        doReturn(true).when(amInternal).isCurrentProfile(anyInt());
         doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());
         doReturn(true).when(amInternal).hasStartedUserState(anyInt());
         doReturn(false).when(amInternal).shouldConfirmCredentials(anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index c45c18d..d68edba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -620,7 +620,7 @@
         final Task pinnedRootTask = mRootWindowContainer.getDefaultTaskDisplayArea()
                 .createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
         final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor)
-                .setParentTask(pinnedRootTask).build();
+                .setParentTaskFragment(pinnedRootTask).build();
         new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
                 .setTask(pinnedTask).build();
         pinnedRootTask.moveToFront("movePinnedRootTaskToFront");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index c35f317..98c1eabe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -21,6 +21,7 @@
 import static com.android.server.wm.testing.Assert.assertThrows;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -36,6 +37,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.view.RemoteAnimationDefinition;
 import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
 import android.window.TaskFragmentCreationParams;
@@ -70,6 +72,7 @@
     private IBinder mFragmentToken;
     private WindowContainerTransaction mTransaction;
     private WindowContainerToken mFragmentWindowToken;
+    private RemoteAnimationDefinition mDefinition;
 
     @Before
     public void setup() {
@@ -83,6 +86,7 @@
                 new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
         mTransaction = new WindowContainerTransaction();
         mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
+        mDefinition = new RemoteAnimationDefinition();
 
         spyOn(mController);
         spyOn(mOrganizer);
@@ -208,6 +212,18 @@
     }
 
     @Test
+    public void testRegisterRemoteAnimations() {
+        mController.registerOrganizer(mIOrganizer);
+        mController.registerRemoteAnimations(mIOrganizer, mDefinition);
+
+        assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
+
+        mController.unregisterRemoteAnimations(mIOrganizer);
+
+        assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
+    }
+
+    @Test
     public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
         mOrganizer.applyTransaction(mTransaction);
 
@@ -326,7 +342,8 @@
         mTransaction.startActivityInTaskFragment(
                 mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
-        mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class));
+        mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
+                null /* options */);
 
         // It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
         // testing the security check here.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 5e4c67c..e528a4a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1716,7 +1716,7 @@
         final Task rootTask = display.getDefaultTaskDisplayArea()
                 .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
         rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+        final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
         // Just work around the unnecessary adjustments for bounds.
         task.getWindowConfiguration().setBounds(bounds);
     }
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..67e8c87 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());
@@ -420,7 +427,7 @@
         TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
         Task rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+        Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
         final Configuration parentConfig = rootTask.getConfiguration();
         parentConfig.windowConfiguration.setBounds(parentBounds);
         parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
@@ -750,7 +757,7 @@
         DisplayInfo displayInfo = new DisplayInfo();
         mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
         final int displayHeight = displayInfo.logicalHeight;
-        final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+        final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
         final Configuration inOutConfig = new Configuration();
         final Configuration parentConfig = new Configuration();
         final int longSide = 1200;
@@ -1368,7 +1375,7 @@
         TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
         Task rootTask = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+        Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
 
         final Configuration parentConfig = rootTask.getConfiguration();
         parentConfig.windowConfiguration.setAppBounds(parentBounds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 45e5f8e..6d60bcf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -41,6 +42,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.window.ITaskOrganizer;
+import android.window.ITransitionPlayer;
 import android.window.TransitionInfo;
 
 import androidx.test.filters.SmallTest;
@@ -444,6 +446,71 @@
                 info.getChange(openInChangeTask.mRemoteToken.toWindowContainerToken()), info));
     }
 
+    @Test
+    public void testIntermediateVisibility() {
+        final TransitionController controller = new TransitionController(mAtm);
+        final ITransitionPlayer player = new ITransitionPlayer.Default();
+        controller.registerTransitionPlayer(player);
+        ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
+        final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
+
+        // Start out with task2 visible and set up a transition that closes task2 and opens task1
+        final Task task1 = createTask(mDisplayContent);
+        task1.mTaskOrganizer = mockOrg;
+        final ActivityRecord activity1 = createActivityRecord(task1);
+        activity1.mVisibleRequested = false;
+        activity1.setVisible(false);
+        final Task task2 = createTask(mDisplayContent);
+        task2.mTaskOrganizer = mockOrg;
+        final ActivityRecord activity2 = createActivityRecord(task1);
+        activity2.mVisibleRequested = true;
+        activity2.setVisible(true);
+
+        openTransition.collectExistenceChange(task1);
+        openTransition.collectExistenceChange(activity1);
+        openTransition.collectExistenceChange(task2);
+        openTransition.collectExistenceChange(activity2);
+
+        activity1.mVisibleRequested = true;
+        activity1.setVisible(true);
+        activity2.mVisibleRequested = false;
+
+        // Using abort to force-finish the sync (since we can't wait for drawing in unit test).
+        // We didn't call abort on the transition itself, so it will still run onTransactionReady
+        // normally.
+        mWm.mSyncEngine.abort(openTransition.getSyncId());
+
+        // Before finishing openTransition, we are now going to simulate closing task1 to return
+        // back to (open) task2.
+        final Transition closeTransition = controller.createTransition(TRANSIT_CLOSE);
+
+        closeTransition.collectExistenceChange(task1);
+        closeTransition.collectExistenceChange(activity1);
+        closeTransition.collectExistenceChange(task2);
+        closeTransition.collectExistenceChange(activity2);
+
+        activity1.mVisibleRequested = false;
+        activity2.mVisibleRequested = true;
+
+        openTransition.finishTransition();
+
+        // We finished the openTransition. Even though activity1 is visibleRequested=false, since
+        // the closeTransition animation hasn't played yet, make sure that we didn't commit
+        // visible=false on activity1 since it needs to remain visible for the animation.
+        assertTrue(activity1.isVisible());
+        assertTrue(activity2.isVisible());
+
+        // Using abort to force-finish the sync (since we obviously can't wait for drawing).
+        // We didn't call abort on the actual transition, so it will still run onTransactionReady
+        // normally.
+        mWm.mSyncEngine.abort(closeTransition.getSyncId());
+
+        closeTransition.finishTransition();
+
+        assertFalse(activity1.isVisible());
+        assertTrue(activity2.isVisible());
+    }
+
     /** Fill the change map with all the parents of top. Change maps are usually fully populated */
     private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes,
             WindowContainer top) {
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..b17ea5e 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,13 +892,17 @@
         assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
     }
 
-    @UseTestDisplay(addWindows = W_INPUT_METHOD)
     @Test
-    public void testAdjustImeInsetsVisibilityWhenTaskSwitchIsAnimating() {
+    public void testAdjustImeInsetsVisibilityWhenSwitchingApps() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+        final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+        spyOn(imeWindow);
+        doReturn(true).when(imeWindow).isVisible();
+        mDisplayContent.mInputMethodWindow = imeWindow;
+
         final InsetsStateController controller = mDisplayContent.getInsetsStateController();
-        controller.getImeSourceProvider().setWindow(mImeWindow, null, null);
+        controller.getImeSourceProvider().setWindow(imeWindow, null, null);
 
         // Simulate app requests IME with updating all windows Insets State when IME is above app.
         mDisplayContent.setImeLayeringTarget(app);
@@ -909,20 +910,20 @@
         assertTrue(mDisplayContent.shouldImeAttachedToApp());
         controller.getImeSourceProvider().scheduleShowImePostLayout(app);
         controller.getImeSourceProvider().getSource().setVisible(true);
-        controller.updateAboveInsetsState(mImeWindow, false);
+        controller.updateAboveInsetsState(imeWindow, 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;
+        // Expect all app windows behind IME can receive IME insets visible.
+        assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+        assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
 
-        // 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());
+        // Simulate app plays closing transition to app2.
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Verify the IME insets is visible on app, but not for app2 during app task switching.
+        assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+        assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
     }
 
     @UseTestDisplay(addWindows = { W_ACTIVITY })
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 050fd80..454ecd7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -56,6 +56,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 
 import static org.junit.Assert.assertEquals;
@@ -66,6 +67,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
@@ -99,6 +101,7 @@
 import android.view.WindowManager.DisplayImePolicy;
 import android.window.ITransitionPlayer;
 import android.window.StartingWindowInfo;
+import android.window.TaskFragmentOrganizer;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 
@@ -589,7 +592,7 @@
     Task createTaskInRootTask(Task rootTask, int userId) {
         final Task task = new TaskBuilder(rootTask.mTaskSupervisor)
                 .setUserId(userId)
-                .setParentTask(rootTask)
+                .setParentTaskFragment(rootTask)
                 .build();
         return task;
     }
@@ -675,6 +678,26 @@
         activity.mVisibleRequested = true;
     }
 
+    /**
+     * Creates a {@link TaskFragment} and attach it to the {@code parentTask}.
+     *
+     * @param parentTask the {@link Task} this TaskFragment is going to be attached
+     * @param createEmbeddedTask Sets to {@code true} to create an embedded Task for this
+     *                           TaskFragment. Otherwise, create a {@link ActivityRecord}.
+     * @return the created TaskFragment
+     */
+    static TaskFragment createTaskFragmentWithParentTask(@NonNull Task parentTask,
+            boolean createEmbeddedTask) {
+        final TaskFragmentBuilder builder = new TaskFragmentBuilder(parentTask.mAtmService)
+                .setParentTask(parentTask);
+        if (createEmbeddedTask) {
+            builder.createEmbeddedTask();
+        } else {
+            builder.createActivityCount(1);
+        }
+        return builder.build();
+    }
+
     /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
     DisplayContent createNewDisplay() {
         return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL);
@@ -857,6 +880,7 @@
         private int mConfigChanges;
         private int mLaunchedFromPid;
         private int mLaunchedFromUid;
+        private String mLaunchedFromPackage;
         private WindowProcessController mWpc;
         private Bundle mIntentExtras;
         private boolean mOnTop = false;
@@ -967,6 +991,11 @@
             return this;
         }
 
+        ActivityBuilder setLaunchedFromPackage(String packageName) {
+            mLaunchedFromPackage = packageName;
+            return this;
+        }
+
         ActivityBuilder setUseProcess(WindowProcessController wpc) {
             mWpc = wpc;
             return this;
@@ -1042,7 +1071,7 @@
                         // Apply the root activity info and intent
                         .setActivityInfo(aInfo)
                         .setIntent(intent)
-                        .setParentTask(mParentTask).build();
+                        .setParentTaskFragment(mParentTask).build();
             } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateRootTask(
                     mParentTask.getWindowingMode(), mParentTask.getActivityType())) {
                 // The parent task can be the task root.
@@ -1056,6 +1085,7 @@
             final ActivityRecord activity = new ActivityRecord.Builder(mService)
                     .setLaunchedFromPid(mLaunchedFromPid)
                     .setLaunchedFromUid(mLaunchedFromUid)
+                    .setLaunchedFromPackage(mLaunchedFromPackage)
                     .setIntent(intent)
                     .setActivityInfo(aInfo)
                     .setActivityOptions(options)
@@ -1101,6 +1131,75 @@
         }
     }
 
+    static class TaskFragmentBuilder {
+        private final ActivityTaskManagerService mAtm;
+        private Task mParentTask;
+        private boolean mCreateParentTask;
+        private boolean mCreateEmbeddedTask;
+        private int mCreateActivityCount = 0;
+        @Nullable
+        private TaskFragmentOrganizer mOrganizer;
+
+        TaskFragmentBuilder(ActivityTaskManagerService service) {
+            mAtm = service;
+        }
+
+        TaskFragmentBuilder setCreateParentTask() {
+            mCreateParentTask = true;
+            return this;
+        }
+
+        TaskFragmentBuilder setParentTask(Task task) {
+            mParentTask = task;
+            return this;
+        }
+
+        /** Creates a child embedded Task and its Activity */
+        TaskFragmentBuilder createEmbeddedTask() {
+            mCreateEmbeddedTask = true;
+            return this;
+        }
+
+        TaskFragmentBuilder createActivityCount(int count) {
+            mCreateActivityCount = count;
+            return this;
+        }
+
+        TaskFragmentBuilder setOrganizer(@Nullable TaskFragmentOrganizer organizer) {
+            mOrganizer = organizer;
+            return this;
+        }
+
+        TaskFragment build() {
+            SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
+
+            final TaskFragment taskFragment = new TaskFragment(mAtm, null /* fragmentToken */,
+                    mOrganizer != null);
+            if (mParentTask == null && mCreateParentTask) {
+                mParentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
+            }
+            if (mParentTask != null) {
+                mParentTask.addChild(taskFragment, POSITION_TOP);
+            }
+            if (mCreateEmbeddedTask) {
+                new TaskBuilder(mAtm.mTaskSupervisor)
+                        .setParentTaskFragment(taskFragment)
+                        .setCreateActivity(true)
+                        .build();
+            }
+            while (mCreateActivityCount > 0) {
+                final ActivityRecord activity = new ActivityBuilder(mAtm).build();
+                taskFragment.addChild(activity);
+                mCreateActivityCount--;
+            }
+            if (mOrganizer != null) {
+                taskFragment.setTaskFragmentOrganizer(
+                        mOrganizer.getOrganizerToken(), 10000 /* pid */);
+            }
+            return taskFragment;
+        }
+    }
+
     /**
      * Builder for creating new tasks.
      */
@@ -1121,7 +1220,7 @@
         private IVoiceInteractionSession mVoiceSession;
 
         private boolean mCreateParentTask = false;
-        private Task mParentTask;
+        private TaskFragment mParentTaskFragment;
 
         private boolean mCreateActivity = false;
 
@@ -1205,8 +1304,8 @@
             return this;
         }
 
-        TaskBuilder setParentTask(Task parentTask) {
-            mParentTask = parentTask;
+        TaskBuilder setParentTaskFragment(TaskFragment parentTaskFragment) {
+            mParentTaskFragment = parentTaskFragment;
             return this;
         }
 
@@ -1219,12 +1318,13 @@
             SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
 
             // Create parent task.
-            if (mParentTask == null && mCreateParentTask) {
-                mParentTask = mTaskDisplayArea.createRootTask(
+            if (mParentTaskFragment == null && mCreateParentTask) {
+                mParentTaskFragment = mTaskDisplayArea.createRootTask(
                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
             }
-            if (mParentTask != null && !Mockito.mockingDetails(mParentTask).isSpy()) {
-                spyOn(mParentTask);
+            if (mParentTaskFragment != null
+                    && !Mockito.mockingDetails(mParentTaskFragment).isSpy()) {
+                spyOn(mParentTaskFragment);
             }
 
             // Create task.
@@ -1252,13 +1352,15 @@
                     .setOnTop(mOnTop)
                     .setVoiceSession(mVoiceSession);
             final Task task;
-            if (mParentTask == null) {
+            if (mParentTaskFragment == null) {
                 task = builder.setActivityType(mActivityType)
                         .setParent(mTaskDisplayArea)
                         .build();
             } else {
-                task = builder.setParent(mParentTask).build();
-                mParentTask.moveToFront("build-task");
+                task = builder.setParent(mParentTaskFragment).build();
+                if (mParentTaskFragment.asTask() != null) {
+                    mParentTaskFragment.asTask().moveToFront("build-task");
+                }
             }
             spyOn(task);
             task.mUserId = mUserId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d048f1842..589f913 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -24,6 +24,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -44,6 +45,7 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 import java.util.function.BiFunction;
 
@@ -126,7 +128,7 @@
         final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
         final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
 
-        mDisplayContent.removeWindowToken(token.token);
+        mDisplayContent.removeWindowToken(token.token, true /* animateExit */);
         // Verify that the token is no longer mapped on the display
         assertNull(mDisplayContent.getWindowToken(token.token));
         // Verify that the token is still attached to its parent
@@ -261,4 +263,29 @@
         assertNotNull(app.getFrozenInsetsState());
         assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState());
     }
+
+    @Test
+    public void testRemoveWindowToken_noAnimateExitWhenSet() {
+        final TestWindowToken token = createTestWindowToken(0, mDisplayContent);
+        final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win");
+        makeWindowVisible(win);
+        assertTrue(win.isOnScreen());
+        spyOn(win);
+        spyOn(win.mWinAnimator);
+        spyOn(win.mToken);
+
+        // Invoking removeWindowToken with setting no window exit animation and not remove window
+        // immediately. verify the window will hide without applying exit animation.
+        mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */,
+                mDisplayContent.mDisplayId);
+        verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */);
+        verify(win).hide(false /* doAnimation */, false /* requestAnim */);
+        assertFalse(win.isOnScreen());
+        verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+        assertTrue(win.mToken.hasChild());
+
+        // Even though the window is being removed afterwards, it won't apply exit animation.
+        win.removeIfPossible();
+        verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1b84927..cf4ef58 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -938,7 +938,7 @@
                             FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
                             uid,
                             event.mPackage,
-                            event.mClass,
+                            "",
                             FrameworkStatsLog
                                     .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_FOREGROUND);
                     // check if this activity has already been resumed
@@ -972,7 +972,7 @@
                                 FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
                                 uid,
                                 event.mPackage,
-                                event.mClass,
+                                "",
                                 FrameworkStatsLog
                                         .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND);
                     }
@@ -1003,7 +1003,7 @@
                                 FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
                                 uid,
                                 event.mPackage,
-                                event.mClass,
+                                "",
                                 FrameworkStatsLog
                                         .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND);
                     }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceLogger.java b/services/usb/java/com/android/server/usb/UsbDeviceLogger.java
new file mode 100644
index 0000000..fab00bc
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbDeviceLogger.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.server.usb;
+
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.dump.DualDumpOutputStream;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.LinkedList;
+
+/**
+* Constructor UsbDeviceLogger class
+*/
+public class UsbDeviceLogger {
+    private final Object mLock = new Object();
+
+    // ring buffer of events to log.
+    @GuardedBy("mLock")
+    private final LinkedList<Event> mEvents;
+
+    private final String mTitle;
+
+    // the maximum number of events to keep in log
+    private final int mMemSize;
+
+    /**
+     * Constructor for Event class.
+     */
+    public abstract static class Event {
+        // formatter for timestamps
+        private static final SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+
+        private final Calendar mCalendar;
+
+        Event() {
+            mCalendar = Calendar.getInstance();
+        }
+
+    /**
+     * Convert event to String
+     * @return StringBuilder
+     */
+        public String toString() {
+            return (new StringBuilder(String.format("%tm-%td %tH:%tM:%tS.%tL",
+                    mCalendar, mCalendar, mCalendar, mCalendar, mCalendar, mCalendar)))
+                    .append(" ").append(eventToString()).toString();
+        }
+
+        /**
+         * Causes the string message for the event to appear in the logcat.
+         * Here is an example of how to create a new event (a StringEvent), adding it to the logger
+         * (an instance of UsbDeviceLoggerr) while also making it show in the logcat:
+         * <pre>
+         *     myLogger.log(
+         *         (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
+         * </pre>
+         * @param tag the tag for the android.util.Log.v
+         * @return the same instance of the event
+         */
+        public Event printLog(String tag) {
+            Log.i(tag, eventToString());
+            return this;
+        }
+
+        /**
+         * Convert event to String.
+         * This method is only called when the logger history is about to the dumped,
+         * so this method is where expensive String conversions should be made, not when the Event
+         * subclass is created.
+         * Timestamp information will be automatically added, do not include it.
+         * @return a string representation of the event that occurred.
+         */
+        public abstract String eventToString();
+    }
+
+    /**
+    * Constructor StringEvent class
+    */
+    public static class StringEvent extends Event {
+        private final String mMsg;
+
+        public StringEvent(String msg) {
+            mMsg = msg;
+        }
+
+        @Override
+        public String eventToString() {
+            return mMsg;
+        }
+    }
+
+    /**
+     * Constructor for logger.
+     * @param size the maximum number of events to keep in log
+     * @param title the string displayed before the recorded log
+     */
+    public UsbDeviceLogger(int size, String title) {
+        mEvents = new LinkedList<Event>();
+        mMemSize = size;
+        mTitle = title;
+    }
+
+    /**
+     * Constructor for logger.
+     * @param evt the maximum number of events to keep in log
+     */
+    public synchronized void log(Event evt) {
+        synchronized (mLock) {
+            if (mEvents.size() >= mMemSize) {
+                mEvents.removeFirst();
+            }
+            mEvents.add(evt);
+        }
+    }
+
+    /**
+     * Constructor for logger.
+     * @param dump the maximum number of events to keep in log
+     * @param id the category of events
+     */
+    public synchronized void dump(DualDumpOutputStream dump, long id) {
+        dump.write("USB Event Log", id, mTitle);
+        for (Event evt : mEvents) {
+            dump.write("USB Event", id, evt.toString());
+        }
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b966643..0d7b23d 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -191,6 +191,8 @@
      */
     private static final int ACCESSORY_HANDSHAKE_TIMEOUT = 10 * 1000;
 
+    private static final int DUMPSYS_LOG_BUFFER = 200;
+
     private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
 
     private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
@@ -210,6 +212,8 @@
     private static Set<Integer> sDenyInterfaces;
     private HashMap<Long, FileDescriptor> mControlFds;
 
+    private static UsbDeviceLogger sEventLogger;
+
     static {
         sDenyInterfaces = new HashSet<>();
         sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
@@ -232,9 +236,11 @@
         @Override
         public void onUEvent(UEventObserver.UEvent event) {
             if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
+            sEventLogger.log(new UsbDeviceLogger.StringEvent("USB UEVENT: " + event.toString()));
 
             String state = event.get("USB_STATE");
             String accessory = event.get("ACCESSORY");
+
             if (state != null) {
                 mHandler.updateState(state);
             } else if ("GETPROTOCOL".equals(accessory)) {
@@ -382,6 +388,8 @@
         mUEventObserver = new UsbUEventObserver();
         mUEventObserver.startObserving(USB_STATE_MATCH);
         mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+
+        sEventLogger = new UsbDeviceLogger(DUMPSYS_LOG_BUFFER, "UsbDeviceManager activity");
     }
 
     UsbProfileGroupSettingsManager getCurrentSettings() {
@@ -814,6 +822,7 @@
 
         protected void sendStickyBroadcast(Intent intent) {
             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+            sEventLogger.log(new UsbDeviceLogger.StringEvent("USB intent: " + intent));
         }
 
         private void updateUsbFunctions() {
@@ -1190,7 +1199,8 @@
                 } else if (mCurrentFunctions == UsbManager.FUNCTION_MIDI) {
                     titleRes = com.android.internal.R.string.usb_midi_notification_title;
                     id = SystemMessage.NOTE_USB_MIDI;
-                } else if (mCurrentFunctions == UsbManager.FUNCTION_RNDIS) {
+                } else if ((mCurrentFunctions == UsbManager.FUNCTION_RNDIS)
+                        || (mCurrentFunctions == UsbManager.FUNCTION_NCM)) {
                     titleRes = com.android.internal.R.string.usb_tether_notification_title;
                     id = SystemMessage.NOTE_USB_TETHER;
                 } else if (mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY) {
@@ -2285,6 +2295,7 @@
 
         if (mHandler != null) {
             mHandler.dump(dump, "handler", UsbDeviceManagerProto.HANDLER);
+            sEventLogger.dump(dump, UsbHandlerProto.UEVENT);
         }
 
         dump.end(token);
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index f638660..bb0c4e9 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -60,7 +60,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.Immutable;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.dump.DualDumpOutputStream;
 
@@ -75,7 +74,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.ProtocolException;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -86,6 +84,8 @@
     private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final int DUMPSYS_LOG_BUFFER = 200;
+
     /** Legacy settings file, before multi-user */
     private static final File sSingleUserSettingsFile = new File(
             "/data/system/usb_device_manager.xml");
@@ -130,6 +130,8 @@
     @GuardedBy("mLock")
     private boolean mIsWriteSettingsScheduled;
 
+    private static UsbDeviceLogger sEventLogger;
+
     /**
      * A package of a user.
      */
@@ -260,6 +262,9 @@
                         device, false /* showMtpNotification */));
 
         mUsbHandlerManager = usbResolveActivityManager;
+
+        sEventLogger = new UsbDeviceLogger(DUMPSYS_LOG_BUFFER,
+                "UsbProfileGroupSettingsManager activity");
     }
 
     /**
@@ -965,6 +970,7 @@
                     matches, mAccessoryPreferenceMap.get(new AccessoryFilter(accessory)));
         }
 
+        sEventLogger.log(new UsbDeviceLogger.StringEvent("accessoryAttached: " + intent));
         resolveActivity(intent, matches, defaultActivity, null, accessory);
     }
 
@@ -1518,6 +1524,7 @@
             }
         }
 
+        sEventLogger.dump(dump, UsbProfileGroupSettingsManagerProto.INTENT);
         dump.end(token);
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index 7b6ccd3..49ea9df 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -689,8 +689,10 @@
         try {
             ApplicationInfo aInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
             if (aInfo.uid != uid) {
-                throw new IllegalArgumentException("package " + packageName
+                Slog.w(TAG, "package " + packageName
                         + " does not match caller's uid " + uid);
+                throw new IllegalArgumentException("package " + packageName
+                        + " not found");
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new IllegalArgumentException("package " + packageName + " not found");
diff --git a/services/usb/lint-baseline.xml b/services/usb/lint-baseline.xml
new file mode 100644
index 0000000..c2c0a35
--- /dev/null
+++ b/services/usb/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
+        errorLine1="        int isDisabled = Settings.Secure.getInt(mContext.getContentResolver(),"
+        errorLine2="                                         ~~~~~~">
+        <location
+            file="frameworks/base/services/usb/java/com/android/server/usb/UsbAlsaManager.java"
+            line="150"
+            column="42"/>
+    </issue>
+
+</issues>
diff --git a/services/uwb/Android.bp b/services/uwb/Android.bp
deleted file mode 100644
index da30d43..0000000
--- a/services/uwb/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
-    name: "services.uwb-sources",
-    srcs: ["java/**/*.java"],
-    path: "java",
-    visibility: ["//frameworks/base/services"],
-}
-
-java_library_static {
-    name: "services.uwb",
-    defaults: ["platform_service_defaults"],
-    srcs: [
-        ":services.uwb-sources",
-    ],
-    libs: [
-        "services.core",
-    ],
-}
diff --git a/services/uwb/OWNERS b/services/uwb/OWNERS
deleted file mode 100644
index c31a2f1..0000000
--- a/services/uwb/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/base:/core/java/android/uwb/OWNERS
diff --git a/services/uwb/java/com/android/server/uwb/UwbInjector.java b/services/uwb/java/com/android/server/uwb/UwbInjector.java
deleted file mode 100644
index 64f1da1..0000000
--- a/services/uwb/java/com/android/server/uwb/UwbInjector.java
+++ /dev/null
@@ -1,83 +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.server.uwb;
-
-import static android.Manifest.permission.UWB_RANGING;
-import static android.content.PermissionChecker.PERMISSION_GRANTED;
-
-import android.annotation.NonNull;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.content.PermissionChecker;
-import android.os.IBinder;
-import android.os.ServiceManager;
-import android.uwb.IUwbAdapter;
-
-
-/**
- * To be used for dependency injection (especially helps mocking static dependencies).
- */
-public class UwbInjector {
-    private static final String TAG = "UwbInjector";
-
-    private static final String VENDOR_SERVICE_NAME = "uwb_vendor";
-
-    private final Context mContext;
-
-    public UwbInjector(@NonNull Context context) {
-        mContext = context;
-    }
-
-    /**
-     * @return Returns the vendor service handle.
-     */
-    public IUwbAdapter getVendorService() {
-        IBinder b = ServiceManager.getService(VENDOR_SERVICE_NAME);
-        if (b == null) return null;
-        return IUwbAdapter.Stub.asInterface(b);
-    }
-
-    /**
-     * Throws security exception if the UWB_RANGING permission is not granted for the calling app.
-     *
-     * <p>Should be used in situations where the app op should not be noted.
-     */
-    public void enforceUwbRangingPermissionForPreflight(
-            @NonNull AttributionSource attributionSource) {
-        if (!attributionSource.checkCallingUid()) {
-            throw new SecurityException("Invalid attribution source " + attributionSource);
-        }
-        int permissionCheckResult = PermissionChecker.checkPermissionForPreflight(
-                mContext, UWB_RANGING, attributionSource);
-        if (permissionCheckResult != PERMISSION_GRANTED) {
-            throw new SecurityException("Caller does not hold UWB_RANGING permission");
-        }
-    }
-
-    /**
-     * Returns true if the UWB_RANGING permission is granted for the calling app.
-     *
-     * <p>Should be used in situations where data will be delivered and hence the app op should
-     * be noted.
-     */
-    public boolean checkUwbRangingPermissionForDataDelivery(
-            @NonNull AttributionSource attributionSource, @NonNull String message) {
-        int permissionCheckResult = PermissionChecker.checkPermissionForDataDelivery(
-                mContext, UWB_RANGING, -1, attributionSource, message);
-        return permissionCheckResult == PERMISSION_GRANTED;
-    }
-}
diff --git a/services/uwb/java/com/android/server/uwb/UwbService.java b/services/uwb/java/com/android/server/uwb/UwbService.java
deleted file mode 100644
index 4bb280f..0000000
--- a/services/uwb/java/com/android/server/uwb/UwbService.java
+++ /dev/null
@@ -1,42 +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.server.uwb;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.android.server.SystemService;
-
-/**
- * Uwb System service.
- */
-public class UwbService extends SystemService {
-    private static final String TAG = "UwbService";
-
-    private final UwbServiceImpl mImpl;
-
-    public UwbService(Context context) {
-        super(context);
-        mImpl = new UwbServiceImpl(context, new UwbInjector(context));
-    }
-
-    @Override
-    public void onStart() {
-        Log.i(TAG, "Registering " + Context.UWB_SERVICE);
-        publishBinderService(Context.UWB_SERVICE, mImpl);
-    }
-}
diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
deleted file mode 100644
index 4dd26a6..0000000
--- a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
+++ /dev/null
@@ -1,325 +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.server.uwb;
-
-import android.annotation.NonNull;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.uwb.IUwbAdapter;
-import android.uwb.IUwbAdapterStateCallbacks;
-import android.uwb.IUwbRangingCallbacks;
-import android.uwb.RangingReport;
-import android.uwb.RangingSession;
-import android.uwb.SessionHandle;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.Map;
-
-/**
- * Implementation of {@link android.uwb.IUwbAdapter} binder service.
- */
-public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRecipient{
-    private static final String TAG = "UwbServiceImpl";
-
-    private final Context mContext;
-    private final UwbInjector mUwbInjector;
-    /**
-     * Map for storing the callbacks wrapper for each session.
-     */
-    @GuardedBy("mCallbacksMap")
-    private final Map<SessionHandle, UwbRangingCallbacksWrapper> mCallbacksMap = new ArrayMap<>();
-
-    /**
-     * Used for caching the vendor implementation of {@link IUwbAdapter} interface.
-     */
-    private IUwbAdapter mVendorUwbAdapter;
-
-    /**
-     * Wrapper for callback registered with vendor service. This wrapper is needed for performing
-     * permission check before sending the callback to the external app.
-     *
-     * Access to these callbacks are synchronized.
-     */
-    private class UwbRangingCallbacksWrapper extends IUwbRangingCallbacks.Stub
-            implements IBinder.DeathRecipient {
-        private final AttributionSource mAttributionSource;
-        private final SessionHandle mSessionHandle;
-        private final IUwbRangingCallbacks mExternalCb;
-        private boolean mIsValid;
-
-        UwbRangingCallbacksWrapper(@NonNull AttributionSource attributionSource,
-                @NonNull SessionHandle sessionHandle,
-                @NonNull IUwbRangingCallbacks externalCb) {
-            mAttributionSource = attributionSource;
-            mSessionHandle = sessionHandle;
-            mExternalCb = externalCb;
-            mIsValid = true;
-
-            // Link to death for external callback.
-            linkToDeath();
-        }
-
-        private void linkToDeath() {
-            IBinder binder = mExternalCb.asBinder();
-            try {
-                binder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Unable to link to client death event.", e);
-            }
-        }
-
-        private void removeClientAndUnlinkToDeath() {
-            // Remove from the map.
-            synchronized (mCallbacksMap) {
-                mCallbacksMap.remove(mSessionHandle);
-            }
-            IBinder binder = mExternalCb.asBinder();
-            binder.unlinkToDeath(this, 0);
-            mIsValid = false;
-        }
-
-
-        @Override
-        public synchronized void onRangingOpened(SessionHandle sessionHandle)
-                throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingOpened(sessionHandle);
-        }
-
-        @Override
-        public synchronized void onRangingOpenFailed(SessionHandle sessionHandle,
-                int reason, PersistableBundle parameters) throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingOpenFailed(sessionHandle, reason, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingStarted(SessionHandle sessionHandle,
-                PersistableBundle parameters)
-                throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingStarted(sessionHandle, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingStartFailed(SessionHandle sessionHandle,
-                int reason, PersistableBundle parameters) throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingStartFailed(sessionHandle, reason, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingReconfigured(SessionHandle sessionHandle,
-                PersistableBundle parameters)
-                throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingReconfigured(sessionHandle, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingReconfigureFailed(SessionHandle sessionHandle,
-                int reason, PersistableBundle parameters) throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingReconfigureFailed(sessionHandle, reason, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingStopped(SessionHandle sessionHandle, int reason,
-                PersistableBundle parameters)
-                throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingStopped(sessionHandle, reason, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingStopFailed(SessionHandle sessionHandle, int reason,
-                PersistableBundle parameters) throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingStopFailed(sessionHandle, reason, parameters);
-        }
-
-        @Override
-        public synchronized void onRangingClosed(SessionHandle sessionHandle, int reason,
-                PersistableBundle parameters) throws RemoteException {
-            if (!mIsValid) return;
-            mExternalCb.onRangingClosed(sessionHandle, reason, parameters);
-            removeClientAndUnlinkToDeath();
-        }
-
-        @Override
-        public synchronized void onRangingResult(SessionHandle sessionHandle,
-                RangingReport rangingReport)
-                throws RemoteException {
-            if (!mIsValid) return;
-            boolean permissionGranted = Binder.withCleanCallingIdentity(
-                    () -> mUwbInjector.checkUwbRangingPermissionForDataDelivery(
-                            mAttributionSource, "uwb ranging result"));
-            if (!permissionGranted) {
-                Log.e(TAG, "Not delivering ranging result because of permission denial"
-                        + mSessionHandle);
-                return;
-            }
-            mExternalCb.onRangingResult(sessionHandle, rangingReport);
-        }
-
-        @Override
-        public synchronized void binderDied() {
-            if (!mIsValid) return;
-            Log.i(TAG, "Client died: ending session: " + mSessionHandle);
-            try {
-                removeClientAndUnlinkToDeath();
-                stopRanging(mSessionHandle);
-                closeRanging(mSessionHandle);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception while handling client death", e);
-            }
-        }
-    }
-
-    private void linkToVendorServiceDeath() {
-        IBinder binder = mVendorUwbAdapter.asBinder();
-        try {
-            binder.linkToDeath(this, 0);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to link to vendor service death event.", e);
-        }
-    }
-
-    @Override
-    public void binderDied() {
-        Log.i(TAG, "Vendor service died: sending session close callbacks");
-        synchronized (mCallbacksMap) {
-            for (Map.Entry<SessionHandle, UwbRangingCallbacksWrapper> e : mCallbacksMap.entrySet()) {
-                try {
-                    e.getValue().mExternalCb.onRangingClosed(
-                            e.getKey(), RangingSession.Callback.REASON_UNKNOWN,
-                            new PersistableBundle());
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Failed to send session close callback " + e.getKey(), ex);
-                }
-            }
-            // Clear all sessions.
-            mCallbacksMap.clear();
-        }
-        mVendorUwbAdapter = null;
-    }
-
-    private synchronized IUwbAdapter getVendorUwbAdapter() throws IllegalStateException {
-        if (mVendorUwbAdapter != null) return mVendorUwbAdapter;
-        mVendorUwbAdapter = mUwbInjector.getVendorService();
-        if (mVendorUwbAdapter == null) {
-            throw new IllegalStateException("No vendor service found!");
-        }
-        Log.i(TAG, "Retrieved vendor service");
-        linkToVendorServiceDeath();
-        return mVendorUwbAdapter;
-    }
-
-    UwbServiceImpl(@NonNull Context context, @NonNull UwbInjector uwbInjector) {
-        mContext = context;
-        mUwbInjector = uwbInjector;
-    }
-
-    private void enforceUwbPrivilegedPermission() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.UWB_PRIVILEGED,
-                "UwbService");
-    }
-
-    @Override
-    public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
-            throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        getVendorUwbAdapter().registerAdapterStateCallbacks(adapterStateCallbacks);
-    }
-
-    @Override
-    public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
-            throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        getVendorUwbAdapter().unregisterAdapterStateCallbacks(adapterStateCallbacks);
-    }
-
-    @Override
-    public long getTimestampResolutionNanos() throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        return getVendorUwbAdapter().getTimestampResolutionNanos();
-    }
-
-    @Override
-    public PersistableBundle getSpecificationInfo() throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        return getVendorUwbAdapter().getSpecificationInfo();
-    }
-
-    @Override
-    public void openRanging(AttributionSource attributionSource,
-            SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks,
-            PersistableBundle parameters) throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        mUwbInjector.enforceUwbRangingPermissionForPreflight(attributionSource);
-
-        UwbRangingCallbacksWrapper wrapperCb =
-                new UwbRangingCallbacksWrapper(attributionSource, sessionHandle, rangingCallbacks);
-        synchronized (mCallbacksMap) {
-            mCallbacksMap.put(sessionHandle, wrapperCb);
-        }
-        getVendorUwbAdapter().openRanging(attributionSource, sessionHandle, wrapperCb, parameters);
-    }
-
-    @Override
-    public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
-            throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        getVendorUwbAdapter().startRanging(sessionHandle, parameters);
-    }
-
-    @Override
-    public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)
-            throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        getVendorUwbAdapter().reconfigureRanging(sessionHandle, parameters);
-    }
-
-    @Override
-    public void stopRanging(SessionHandle sessionHandle) throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        getVendorUwbAdapter().stopRanging(sessionHandle);
-    }
-
-    @Override
-    public void closeRanging(SessionHandle sessionHandle) throws RemoteException {
-        enforceUwbPrivilegedPermission();
-        getVendorUwbAdapter().closeRanging(sessionHandle);
-    }
-
-    @Override
-    public synchronized int getAdapterState() throws RemoteException {
-        return getVendorUwbAdapter().getAdapterState();
-    }
-
-    @Override
-    public synchronized void setEnabled(boolean enabled) throws RemoteException {
-        getVendorUwbAdapter().setEnabled(enabled);
-    }
-}
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 68b2e61..c0c3e6f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
@@ -60,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();
     }
 
@@ -71,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);
     }
@@ -80,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);
     }
 
@@ -109,9 +114,15 @@
     }
 
     // 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;
+        }
     }
 
     /**
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 402b70b..93989b6 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -89,6 +89,13 @@
                                      boolean allowInteractiveResponse);
 
     /**
+     * Telecom calls this method when times out waiting for the {@link CallRedirectionService} to
+     * call {@link #placeCallUnmodified()}, {@link #redirectCall(Uri, PhoneAccountHandle, boolean)},
+     * or {@link #cancelCall()}
+     */
+    public void onRedirectionTimeout() {}
+
+    /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
      * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
      * no changes are required to the outgoing call, and that the call should be placed as-is.
@@ -167,6 +174,12 @@
     private static final int MSG_PLACE_CALL = 1;
 
     /**
+     * A handler message to process the attempt to notify the operation of redirection service timed
+     * out from Telecom
+     */
+    private static final int MSG_TIMEOUT = 2;
+
+    /**
      * A handler to process the attempt to place call with redirection service from Telecom
      */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -183,6 +196,9 @@
                         args.recycle();
                     }
                     break;
+                case MSG_TIMEOUT:
+                    onRedirectionTimeout();
+                    break;
             }
         }
     };
@@ -209,6 +225,15 @@
             args.arg4 = allowInteractiveResponse;
             mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
         }
+
+        /**
+         * Telecom calls this method to inform the CallRedirectionService of the timeout waiting for
+         * it to complete its operation.
+         */
+        @Override
+        public void notifyTimeout() {
+            mHandler.obtainMessage(MSG_TIMEOUT).sendToTarget();
+        }
     }
 
     @Override
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index c365648..cac716e 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -81,7 +81,8 @@
  * <pre>
  * {@code
  * <service android:name="your.package.YourInCallServiceImplementation"
- *          android:permission="android.permission.BIND_INCALL_SERVICE">
+ *          android:permission="android.permission.BIND_INCALL_SERVICE"
+ *          android:exported="true">
  *      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
  *      <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
  *          android:value="true" />
@@ -91,6 +92,10 @@
  * </service>
  * }
  * </pre>
+ *
+ * <em>Note: You should NOT mark your {@link InCallService} with the attribute
+ * {@code android:exported="false"}; doing so can result in a failure to bind to your implementation
+ * during calls.</em>
  * <p>
  * In addition to implementing the {@link InCallService} API, you must also declare an activity in
  * your manifest which handles the {@link Intent#ACTION_DIAL} intent.  The example below illustrates
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 02bd001..bc0a146 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -23,6 +23,8 @@
 import android.os.Bundle;
 import android.util.ArrayMap;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -115,6 +117,7 @@
     public static final int SDK_VERSION_R = 30;
 
     // A Map allows us to track each Call by its Telecom-specified call ID
+    @GuardedBy("mLock")
     private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>();
 
     // A List allows us to keep the Calls in a stable iteration order so that casually developed
@@ -154,7 +157,7 @@
             return;
         }
 
-        Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+        Call call = getCallById(parcelableCall.getId());
         if (call == null) {
             call = new Call(this, parcelableCall.getId(), mInCallAdapter,
                     parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
@@ -191,14 +194,14 @@
         if (mTargetSdkVersion < SDK_VERSION_R
                 && parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) {
             Log.i(this, "removing audio processing call during update for sdk compatibility");
-            Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+            Call call = getCallById(parcelableCall.getId());
             if (call != null) {
                 internalRemoveCall(call);
             }
             return;
         }
 
-        Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+        Call call = getCallById(parcelableCall.getId());
         if (call != null) {
             checkCallTree(parcelableCall);
             call.internalUpdate(parcelableCall, mCallByTelecomCallId);
@@ -215,8 +218,14 @@
         }
     }
 
+    Call getCallById(String callId) {
+        synchronized (mLock) {
+            return mCallByTelecomCallId.get(callId);
+        }
+    }
+
     final void internalSetPostDialWait(String telecomId, String remaining) {
-        Call call = mCallByTelecomCallId.get(telecomId);
+        Call call = getCallById(telecomId);
         if (call != null) {
             call.internalSetPostDialWait(remaining);
         }
@@ -230,7 +239,7 @@
     }
 
     final Call internalGetCallByTelecomId(String telecomId) {
-        return mCallByTelecomCallId.get(telecomId);
+        return getCallById(telecomId);
     }
 
     final void internalBringToForeground(boolean showDialpad) {
@@ -249,35 +258,35 @@
     }
 
     final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) {
-        Call call = mCallByTelecomCallId.get(telecomId);
+        Call call = getCallById(telecomId);
         if (call != null) {
             call.internalOnConnectionEvent(event, extras);
         }
     }
 
     final void internalOnRttUpgradeRequest(String callId, int requestId) {
-        Call call = mCallByTelecomCallId.get(callId);
+        Call call = getCallById(callId);
         if (call != null) {
             call.internalOnRttUpgradeRequest(requestId);
         }
     }
 
     final void internalOnRttInitiationFailure(String callId, int reason) {
-        Call call = mCallByTelecomCallId.get(callId);
+        Call call = getCallById(callId);
         if (call != null) {
             call.internalOnRttInitiationFailure(reason);
         }
     }
 
     final void internalOnHandoverFailed(String callId, int error) {
-        Call call = mCallByTelecomCallId.get(callId);
+        Call call = getCallById(callId);
         if (call != null) {
             call.internalOnHandoverFailed(error);
         }
     }
 
     final void internalOnHandoverComplete(String callId) {
-        Call call = mCallByTelecomCallId.get(callId);
+        Call call = getCallById(callId);
         if (call != null) {
             call.internalOnHandoverComplete();
         }
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index c1bc440..ce1938b 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -31,4 +31,6 @@
 oneway interface ICallRedirectionService {
     void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
             in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
+
+    void notifyTimeout();
 }
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/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 73d1710..a0b8970 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -774,37 +774,6 @@
     }
 
     /**
-     * Send a text based SMS without writing it into the SMS Provider.
-     *
-     * <p>Requires Permission:
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
-     * privileges.
-     * </p>
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the SMS being sent on the subscription associated with logical
-     * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
-     * correct subscription.
-     * </p>
-     *
-     * @see #sendTextMessage(String, String, String, PendingIntent,
-     * PendingIntent, int, boolean, int)
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public void sendTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent, int priority,
-            boolean expectMore, int validityPeriod) {
-        sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                false /* persistMessage */, priority, expectMore, validityPeriod);
-    }
-
-    /**
      *
      * Inject an SMS PDU into the android application framework.
      *
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 114c90b..3b44a34 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1847,8 +1847,9 @@
      * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
      * @hide
      */
-    public void addSubscriptionInfoRecord(String uniqueId, String displayName, int slotIndex,
-            int subscriptionType) {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void addSubscriptionInfoRecord(@NonNull String uniqueId, @Nullable String displayName,
+            int slotIndex, int subscriptionType) {
         if (VDBG) {
             logd("[addSubscriptionInfoRecord]+ uniqueId:" + uniqueId
                     + ", displayName:" + displayName + ", slotIndex:" + slotIndex
@@ -1883,7 +1884,8 @@
      * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
      * @hide
      */
-    public void removeSubscriptionInfoRecord(String uniqueId, int subscriptionType) {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void removeSubscriptionInfoRecord(@NonNull String uniqueId, int subscriptionType) {
         if (VDBG) {
             logd("[removeSubscriptionInfoRecord]+ uniqueId:" + uniqueId
                     + ", subscriptionType: " + subscriptionType);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 412c02c..39cb04a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3483,7 +3483,8 @@
      */
     private int getLogicalSlotIndex(int physicalSlotIndex) {
         UiccSlotInfo[] slotInfos = getUiccSlotsInfo();
-        if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length) {
+        if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length
+                && slotInfos[physicalSlotIndex] != null) {
             return slotInfos[physicalSlotIndex].getLogicalSlotIdx();
         }
 
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 0aff997..dfe5e6c9 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -766,7 +766,10 @@
      * The method is only valid to call when the session state is in
      * {@link ImsCallSession.State#IDLE}.
      *
-     * @param callee dialed string to make the call to
+     * @param callee dial string to make the call to.  The platform passes the dialed number
+     *               entered by the user as-is.  The {@link ImsService} should ensure that the
+     *               number is formatted in SIP messages appropriately (e.g. using
+     *               {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}).
      * @param profile call profile to make the call with the specified service type,
      *      call type and media information
      * @see Listener#callSessionStarted, Listener#callSessionStartFailed
@@ -788,7 +791,10 @@
      * The method is only valid to call when the session state is in
      * {@link ImsCallSession.State#IDLE}.
      *
-     * @param participants participant list to initiate an IMS conference call
+     * @param participants participant list to initiate an IMS conference call.  The platform passes
+     *               the dialed numbers entered by the user as-is.  The {@link ImsService} should
+     *               ensure that the number is formatted in SIP messages appropriately (e.g. using
+     *               {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}).
      * @param profile call profile to make the call with the specified service type,
      *      call type and media information
      * @see Listener#callSessionStarted, Listener#callSessionStartFailed
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/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
index 1a1c7f8..43273a4 100755
--- a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
@@ -25,6 +25,7 @@
 {
     void onError(int errorCode, String message);
 
+    @SuppressWarnings(value={"untyped-collection"})
     void onAvailableSaisUpdated(in List currentSai, in List availableSais);
 
     void onServiceInterfaceAvailable(String interfaceName, int index);
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
index 44cc24a..6e139ac 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
@@ -29,9 +29,11 @@
 
     void stopGroupCall(int subId, long tmgi);
 
+    @SuppressWarnings(value={"untyped-collection"})
     void updateGroupCall(int subscriptionId, long tmgi, in List saiList,
         in List frequencyList);
 
+    @SuppressWarnings(value={"untyped-collection"})
     int startGroupCall(int subscriptionId, long tmgi, in List saiList,
         in List frequencyList, IGroupCallCallback callback);
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4fc7776..4f3b4cb 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1975,6 +1975,7 @@
     /**
      * Return the emergency number list from all the active subscriptions.
      */
+    @SuppressWarnings(value={"untyped-collection"})
     Map getEmergencyNumberList(String callingPackage, String callingFeatureId);
 
     /**
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 7a1dda3..49daad3 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -573,11 +573,26 @@
 
     /** @hide */
     @Override
+    @SystemApi
+    public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+            IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
     public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
             IntentFilter filter, String broadcastPermission, Handler scheduler) {
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void unregisterReceiver(BroadcastReceiver receiver) {
         throw new UnsupportedOperationException();
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/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 08c9e5d..2cc1943 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -36,30 +36,35 @@
     }
 }
 
+/**
+ * If [allStates] is true, checks if the stack space of all displays is fully covered
+ * by any visible layer, during the whole transitions
+ *
+ * Otherwise, checks if the stack space of all displays is fully covered
+ * by any visible layer, at the start and end of the transition
+ *
+ * @param allStates if all states should be checked, othersie, just initial and final
+ */
 @JvmOverloads
-fun FlickerTestParameter.entireScreenCovered(
-    beginRotation: Int,
-    endRotation: Int = beginRotation,
-    allStates: Boolean = true
-) {
-    val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
-    val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+fun FlickerTestParameter.entireScreenCovered(allStates: Boolean = true) {
     if (allStates) {
         assertLayers {
-            if (startingBounds == endingBounds) {
-                this.coversAtLeast(startingBounds)
-            } else {
-                this.coversAtLeast(startingBounds)
-                    .then()
-                    .coversAtLeast(endingBounds)
+            this.invoke("entireScreenCovered") { entry ->
+                entry.entry.displays.forEach { display ->
+                    entry.visibleRegion().coversAtLeast(display.layerStackSpace)
+                }
             }
         }
     } else {
         assertLayersStart {
-            this.visibleRegion().coversAtLeast(startingBounds)
+            this.entry.displays.forEach { display ->
+                this.visibleRegion().coversAtLeast(display.layerStackSpace)
+            }
         }
         assertLayersEnd {
-            this.visibleRegion().coversAtLeast(endingBounds)
+            this.entry.displays.forEach { display ->
+                this.visibleRegion().coversAtLeast(display.layerStackSpace)
+            }
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 90c851d..22bf57a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -23,7 +23,7 @@
 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.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -39,7 +39,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
+@Group4
 class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index e8391ed..a1c0e01 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -22,7 +22,7 @@
 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.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -38,7 +38,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
+@Group4
 class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index f9e6bab..3c610af 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -123,9 +123,7 @@
 
     @Presubmit
     @Test
-    open fun entireScreenCovered() {
-        testSpec.entireScreenCovered(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
+    open fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 384d8e8..d17e77d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -119,7 +119,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index ade215b..6f0f55a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -116,8 +116,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
-        Surface.ROTATION_0)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index cdfcff3..6cdf32c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -115,7 +115,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 05fc267..8aaf925 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -125,8 +125,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
-        Surface.ROTATION_0)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index f35a180..665204b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -108,7 +108,7 @@
 
     @Presubmit
     @Test
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 3bcf793..fe1b1cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -143,8 +143,7 @@
     @Presubmit
     @Test
     // During testing the launcher is always in portrait mode
-    fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
-        testSpec.config.endRotation)
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index f9dd88e..1c32e32 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -28,7 +28,7 @@
 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.Group2
+import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
@@ -52,7 +52,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group2
+@Group4
 @Presubmit
 class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
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
index 70a79d1..3e35e21 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.launch
 
 import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.entireScreenCovered
@@ -27,8 +27,7 @@
 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.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -46,7 +45,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group1
+@Group4
 class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
     val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
@@ -76,7 +75,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun finishSubActivity() {
         testSpec.assertWm {
@@ -88,13 +87,11 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
-    fun entireScreenCovered() {
-        testSpec.entireScreenCovered(testSpec.config.startRotation)
-    }
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun launcherWindowNotVisible() {
         testSpec.assertWm {
@@ -102,7 +99,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun launcherLayerNotVisible() {
         testSpec.assertLayers { this.isInvisible(LAUNCHER_COMPONENT) }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index e6dc852..be919cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -33,8 +35,21 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test cold launch app from launcher.
+ * Test cold launching an app from launcher
+ *
  * To run this test: `atest FlickerTests:OpenAppColdTest`
+ *
+ * Actions:
+ *     Make sure no apps are running on the device
+ *     Launch an app [testApp] and wait animation to complete
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited [OpenAppTransition]
+ *     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)
@@ -42,6 +57,9 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group1
 class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    /**
+     * Defines the transition used to run the test
+     */
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
@@ -62,25 +80,46 @@
             }
         }
 
+    /** {@inheritDoc} */
     @FlakyTest
     @Test
     override fun navBarLayerRotatesAndScales() {
         super.navBarLayerRotatesAndScales()
     }
 
-    @FlakyTest(bugId = 192721431)
+    /** {@inheritDoc} */
+    @Postsubmit
     @Test
-    override fun appLayerReplacesLauncher() {
-        super.appLayerReplacesLauncher()
-    }
+    override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
 
-    @FlakyTest(bugId = 192721431)
+    /** {@inheritDoc} */
+    @Postsubmit
     @Test
-    override fun appWindowReplacesLauncherAsTopWindow() {
+    override fun appWindowReplacesLauncherAsTopWindow() =
         super.appWindowReplacesLauncherAsTopWindow()
-    }
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun launcherWindowBecomesInvisible() = super.launcherWindowBecomesInvisible()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
 
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 7833e2f..3678f33 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -33,8 +34,23 @@
 import org.junit.runners.Parameterized
 
 /**
- * Launch an app from the recents app view (the overview)
+ * Test launching an app from the recents app view (the overview)
+ *
  * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ *
+ * Actions:
+ *     Launch [testApp]
+ *     Press recents
+ *     Relaunch an app [testApp] by selecting it in the overview screen, and wait animation to
+ *     complete (only this action is traced)
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited [OpenAppTransition]
+ *     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)
@@ -42,6 +58,9 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group1
 class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    /**
+     * Defines the transition used to run the test
+     */
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
@@ -63,13 +82,38 @@
             }
         }
 
+    /** {@inheritDoc} */
     @FlakyTest
     @Test
-    override fun navBarLayerRotatesAndScales() {
-        super.navBarLayerRotatesAndScales()
-    }
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun launcherWindowBecomesInvisible() = super.launcherWindowBecomesInvisible()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
 
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
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
index 7077d3b..b717612 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.content.ComponentName
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
@@ -28,6 +30,7 @@
 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 com.google.common.truth.Truth
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -35,8 +38,21 @@
 import org.junit.runners.Parameterized
 
 /**
- * Launch an app while the phone is locked
+ * Test launching an app while the device is locked
+ *
  * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ *
+ * Actions:
+ *     Lock the device.
+ *     Launch an app on top of the lock screen [testApp] and wait animation to complete
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited [OpenAppTransition]
+ *     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)
@@ -45,14 +61,20 @@
 @Group1
 class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
     override val testApp = NonResizeableAppHelper(instrumentation)
+    private val colorFadComponent = ComponentName("", "ColorFade BLAST#")
 
+    /**
+     * Defines the transition used to run the test
+     */
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-        get() = {
-            super.transition(this, it)
+        get() = { args ->
+            super.transition(this, args)
             setup {
                 eachRun {
                     device.sleep()
-                    wmHelper.waitForAppTransitionIdle()
+                    wmHelper.waitFor("noAppWindowsOnTop") {
+                        it.wmState.topVisibleAppWindow.isEmpty()
+                    }
                 }
             }
             teardown {
@@ -66,17 +88,29 @@
             }
         }
 
+    /**
+     * Checks that the nav bar layer starts visible, becomes invisible during unlocking animation
+     * and becomes visible at the end
+     */
     @Presubmit
     @Test
-    override fun navBarLayerIsVisible() {
-        testSpec.assertLayersEnd {
-            isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+    fun navBarLayerVisibilityChanges() {
+        testSpec.assertLayers {
+            this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+                .then()
+                .isInvisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+                .then()
+                .isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
         }
     }
 
+    /**
+     * Checks that the app layer doesn't exist at the start of the transition, that it is
+     * created (invisible) and becomes visible during the transition
+     */
     @Presubmit
     @Test
-    fun nonResizableAppLayerBecomesVisible() {
+    fun appLayerBecomesVisible() {
         testSpec.assertLayers {
             this.notContains(testApp.component)
                     .then()
@@ -86,9 +120,16 @@
         }
     }
 
+    /**
+     * Checks that the app window doesn't exist at the start of the transition, that it is
+     * created (invisible - optional) and becomes visible during the transition
+     *
+     * The `isAppWindowInvisible` step is optional because we log once per frame, upon logging,
+     * the window may be visible or not depending on what was processed until that moment.
+     */
     @Presubmit
     @Test
-    fun nonResizableAppWindowBecomesVisible() {
+    fun appWindowBecomesVisible() {
         testSpec.assertWm {
             this.notContains(testApp.component)
                     .then()
@@ -99,62 +140,95 @@
         }
     }
 
+    /**
+     * Checks if [testApp] is visible at the end of the transition
+     */
     @Presubmit
     @Test
-    fun nonResizableAppWindowBecomesVisibleAtEnd() {
+    fun appWindowBecomesVisibleAtEnd() {
         testSpec.assertWmEnd {
             this.isVisible(testApp.component)
         }
     }
 
-    @FlakyTest
+    /**
+     * Checks that the nav bar starts the transition visible, then becomes invisible during
+     * then unlocking animation and becomes visible at the end of the transition
+     */
+    @Postsubmit
     @Test
-    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+    fun navBarWindowsVisibilityChanges() {
+        testSpec.assertWm {
+            this.isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+                .then()
+                .isNonAppWindowInvisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+                .then()
+                .isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+        }
+    }
 
-    @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()
-
+    /** {@inheritDoc} */
     @FlakyTest
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
             super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 
+    /** {@inheritDoc} */
     @FlakyTest
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
             super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @FlakyTest
+    /** {@inheritDoc} */
+    @Postsubmit
     @Test
     override fun entireScreenCovered() = super.entireScreenCovered()
 
+    /**
+     * Checks that the focus changes from the launcher to [testApp]
+     */
     @FlakyTest
     @Test
     override fun focusChanges() = super.focusChanges()
 
-    @FlakyTest
+    /**
+     * Checks that the screen is locked at the start of the transition ([colorFadComponent])
+     * layer is visible
+     */
+    @Postsubmit
     @Test
-    override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+    fun screenLockedStart() {
+        testSpec.assertLayersStart {
+            isVisible(colorFadComponent)
+        }
+    }
 
-    @FlakyTest
+    /**
+     * This test checks if the launcher is visible at the start and the app at the end,
+     * it cannot use the regular assertion (check over time), because on lock screen neither
+     * the app not the launcher are visible, and there is no top visible window.
+     */
+    @Postsubmit
     @Test
-    override fun appWindowReplacesLauncherAsTopWindow() =
-            super.appWindowReplacesLauncherAsTopWindow()
+    override fun appWindowReplacesLauncherAsTopWindow() {
+        testSpec.assertWm {
+            this.invoke("noAppWindowsOnTop") {
+                    Truth.assertWithMessage("Should not have any app window on top " +
+                        "when the screen is locked")
+                        .that(it.wmState.topVisibleAppWindow)
+                        .isEmpty()
+                }.then()
+                .isAppWindowOnTop(testApp.component)
+        }
+    }
 
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
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 1435120..14d17f8 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
@@ -40,12 +40,16 @@
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SPLASH_SCREEN_COMPONENT
 import org.junit.Test
 
 abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
 
+    /**
+     * Defines the transition used to run the test
+     */
     protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
         withTestName { testSpec.name }
         repeat { testSpec.config.repetitions }
@@ -62,6 +66,10 @@
         }
     }
 
+    /**
+     * Entry point for the test runner. It will use this method to initialize and cache
+     * flicker executions
+     */
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
@@ -69,42 +77,60 @@
         }
     }
 
-    @Presubmit
-    @Test
+    /**
+     * Checks that the navigation bar window is visible during the whole transition
+     */
     open fun navBarWindowIsVisible() {
         testSpec.navBarWindowIsVisible()
     }
 
-    @Presubmit
-    @Test
+    /**
+     * Checks that the navigation bar layer is visible during the whole transition
+     */
     open fun navBarLayerIsVisible() {
         testSpec.navBarLayerIsVisible()
     }
 
+    /**
+     * Checks the position of the navigation bar at the start and end of the transition
+     */
     @Presubmit
     @Test
     open fun navBarLayerRotatesAndScales() {
         testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
     }
 
+    /**
+     * Checks that the status bar window is visible during the whole transition
+     */
     @Presubmit
     @Test
     open fun statusBarWindowIsVisible() {
         testSpec.statusBarWindowIsVisible()
     }
 
+    /**
+     * Checks that the status bar layer is visible during the whole transition
+     */
     @Presubmit
     @Test
     open fun statusBarLayerIsVisible() {
         testSpec.statusBarLayerIsVisible()
     }
 
+    /**
+     * Checks the position of the status bar at the start and end of the transition
+     */
     @Presubmit
     @Test
     open fun statusBarLayerRotatesScales() {
         testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
     }
 
+    /**
+     * Checks that all windows that are visible on the trace, are visible for at least 2
+     * consecutive entries.
+     */
     @Presubmit
     @Test
     open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
@@ -113,6 +139,10 @@
         }
     }
 
+    /**
+     * Checks that all layers that are visible on the trace, are visible for at least 2
+     * consecutive entries.
+     */
     @Presubmit
     @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
@@ -121,13 +151,16 @@
         }
     }
 
+    /**
+     * Checks that all parts of the screen are covered during the transition
+     */
     @Presubmit
     @Test
-    // During testing the launcher is always in portrait mode
-    open fun entireScreenCovered() {
-        testSpec.entireScreenCovered(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
+    open fun entireScreenCovered() = testSpec.entireScreenCovered()
 
+    /**
+     * Checks that the focus changes from the launcher to [testApp]
+     */
     @Presubmit
     @Test
     open fun focusChanges() {
@@ -136,12 +169,19 @@
         }
     }
 
-    @Presubmit
-    @Test
+    /**
+     * Checks that [LAUNCHER_COMPONENT] layer is visible at the start of the transition, and
+     * is replaced by [testApp], which remains visible until the end
+     */
     open fun appLayerReplacesLauncher() {
         testSpec.replacesLayer(LAUNCHER_COMPONENT, testApp.component)
     }
 
+    /**
+     * Checks that [LAUNCHER_COMPONENT] window is visible at the start of the transition, and
+     * is replaced by a snapshot or splash screen (optional), and finally, is replaced by
+     * [testApp], which remains visible until the end
+     */
     @Presubmit
     @Test
     open fun appWindowReplacesLauncherAsTopWindow() {
@@ -150,12 +190,16 @@
                     .then()
                     .isAppWindowOnTop(SNAPSHOT_COMPONENT, isOptional = true)
                     .then()
+                    .isAppWindowOnTop(SPLASH_SCREEN_COMPONENT, isOptional = true)
+                    .then()
                     .isAppWindowOnTop(testApp.component)
         }
     }
 
-    @Presubmit
-    @Test
+    /**
+     * Checks that [LAUNCHER_COMPONENT] window is visible at the start, and
+     * becomes invisible during the transition
+     */
     open fun launcherWindowBecomesInvisible() {
         testSpec.assertWm {
             this.isAppWindowVisible(LAUNCHER_COMPONENT)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index b509c61..5edee0c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -32,8 +33,22 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test warm launch app.
+ * Test warm launching an app from launcher
+ *
  * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ *
+ * Actions:
+ *     Launch [testApp]
+ *     Press home
+ *     Relaunch an app [testApp] and wait animation to complete (only this action is traced)
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited [OpenAppTransition]
+ *     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 +56,9 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group1
 class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    /**
+     * Defines the transition used to run the test
+     */
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
@@ -65,11 +83,38 @@
             }
         }
 
+    /** {@inheritDoc} */
     @FlakyTest
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun launcherWindowBecomesInvisible() = super.launcherWindowBecomesInvisible()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
new file mode 100644
index 0000000..035aac1
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -0,0 +1,331 @@
+/*
+ * 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.quickswitch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.RequiresDevice
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.platform.app.InstrumentationRegistry
+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.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isRotated
+import com.android.server.wm.flicker.navBarLayerIsVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching back to previous app from last opened app
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
+ *
+ * Actions:
+ *     Launch an app [testApp1]
+ *     Launch another app [testApp2]
+ *     Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
+ *
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+    private val testApp1 = SimpleAppHelper(instrumentation)
+    private val testApp2 = NonResizeableAppHelper(instrumentation)
+
+    private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            setup {
+                eachRun {
+                    testApp1.launchViaIntent(wmHelper)
+                    wmHelper.waitForFullScreenApp(testApp1.component)
+
+                    testApp2.launchViaIntent(wmHelper)
+                    wmHelper.waitForFullScreenApp(testApp2.component)
+                }
+            }
+            transitions {
+                // Swipe right from bottom to quick switch back
+                // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
+                // as to not accidentally trigger a swipe back or forward action which would result
+                // in the same behavior but not testing quick swap.
+                device.swipe(
+                        startDisplayBounds.bounds.right / 3,
+                        startDisplayBounds.bounds.bottom,
+                        2 * startDisplayBounds.bounds.right / 3,
+                        startDisplayBounds.bounds.bottom,
+                        if (testSpec.config.startRotation.isRotated()) 75 else 30
+                )
+
+                wmHelper.waitForFullScreenApp(testApp1.component)
+                wmHelper.waitForAppTransitionIdle()
+            }
+
+            teardown {
+                test {
+                    testApp1.exit()
+                    testApp2.exit()
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks that the transition starts with [testApp2]'s windows filling/covering exactly the
+     * entirety of the display.
+     */
+    @Postsubmit
+    @Test
+    fun startsWithApp2WindowsCoverFullScreen() {
+        testSpec.assertWmStart {
+            this.frameRegion(testApp2.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with [testApp2]'s layers filling/covering exactly the
+     * entirety of the display.
+     */
+    @Postsubmit
+    @Test
+    fun startsWithApp2LayersCoverFullScreen() {
+        testSpec.assertLayersStart {
+            this.visibleRegion(testApp2.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with [testApp2] being the top window.
+     */
+    @Postsubmit
+    @Test
+    fun startsWithApp2WindowBeingOnTop() {
+        testSpec.assertWmStart {
+            this.isAppWindowOnTop(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp1] windows fill the entire screen (i.e. is "fullscreen") at the end of the
+     * transition once we have fully quick switched from [testApp2] back to the [testApp1].
+     */
+    @Postsubmit
+    @Test
+    fun endsWithApp1WindowsCoveringFullScreen() {
+        testSpec.assertWmEnd {
+            this.frameRegion(testApp1.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that [testApp1] layers fill the entire screen (i.e. is "fullscreen") at the end of the
+     * transition once we have fully quick switched from [testApp2] back to the [testApp1].
+     */
+    @Postsubmit
+    @Test
+    fun endsWithApp1LayersCoveringFullScreen() {
+        testSpec.assertLayersEnd {
+            this.visibleRegion(testApp1.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that [testApp1] is the top window at the end of the transition once we have fully quick
+     * switched from [testApp2] back to the [testApp1].
+     */
+    @Postsubmit
+    @Test
+    fun endsWithApp1BeingOnTop() {
+        testSpec.assertWmEnd {
+            this.isAppWindowOnTop(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp1]'s window starts off invisible and becomes visible at some point before
+     * the end of the transition and then stays visible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app1WindowBecomesAndStaysVisible() {
+        testSpec.assertWm {
+            this.isAppWindowInvisible(testApp1.component)
+                    .then()
+                    .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(testApp1.component, ignoreActivity = true)
+        }
+    }
+
+    /**
+     * Checks that [testApp1]'s layer starts off invisible and becomes visible at some point before
+     * the end of the transition and then stays visible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app1LayerBecomesAndStaysVisible() {
+        testSpec.assertLayers {
+            this.isInvisible(testApp1.component)
+                    .then()
+                    .isVisible(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp2]'s window starts off visible and becomes invisible at some point before
+     * the end of the transition and then stays invisible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app2WindowBecomesAndStaysInvisible() {
+        testSpec.assertWm {
+            this.isAppWindowVisible(testApp2.component, ignoreActivity = true)
+                    .then()
+                    .isAppWindowInvisible(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp2]'s layer starts off visible and becomes invisible at some point before
+     * the end of the transition and then stays invisible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app2LayerBecomesAndStaysInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(testApp2.component)
+                    .then()
+                    .isInvisible(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp2]'s window is visible at least until [testApp1]'s window is visible.
+     * Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially
+     * visible.
+     */
+    @Postsubmit
+    @Test
+    fun app1WindowIsVisibleOnceApp2WindowIsInvisible() {
+        testSpec.assertWm {
+            this.isAppWindowVisible(testApp2.component)
+                    .then()
+                    // TODO: Do we actually want to test this? Seems too implementation specific...
+                    .isAppWindowVisible(LAUNCHER_COMPONENT, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp2]'s layer is visible at least until [testApp1]'s window is visible.
+     * Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially
+     * visible.
+     */
+    @Postsubmit
+    @Test
+    fun app1LayerIsVisibleOnceApp2LayerIsInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(testApp2.component)
+                    .then()
+                    .isVisible(LAUNCHER_COMPONENT, isOptional = true)
+                    .then()
+                    .isVisible(SNAPSHOT_COMPONENT, isOptional = true)
+                    .then()
+                    .isVisible(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that the navbar window is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
+
+    /**
+     * Checks that the navbar layer is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible()
+
+    /**
+     * Checks that the navbar is always in the right position and covers the expected region.
+     *
+     * NOTE: This doesn't check that the navbar is visible or not.
+     */
+    @Postsubmit
+    @Test
+    fun navbarIsAlwaysInRightPosition() =
+            testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+
+    /**
+     * Checks that the status bar window is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
+
+    /**
+     * Checks that the status bar layer is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
+
+    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, Surface.ROTATION_90)
+                    )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
new file mode 100644
index 0000000..b975360
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -0,0 +1,348 @@
+/*
+ * 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.quickswitch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.RequiresDevice
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.platform.app.InstrumentationRegistry
+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.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isRotated
+import com.android.server.wm.flicker.navBarLayerIsVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching back to previous app from last opened app
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
+ *
+ * Actions:
+ *     Launch an app [testApp1]
+ *     Launch another app [testApp2]
+ *     Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
+ *     Swipe left from the bottom of the screen to quick switch forward to the second app [testApp2]
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestParameter) {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+    private val testApp1 = SimpleAppHelper(instrumentation)
+    private val testApp2 = NonResizeableAppHelper(instrumentation)
+
+    private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            withTestName { testSpec.name }
+            repeat { testSpec.config.repetitions }
+            setup {
+                eachRun {
+                    testApp1.launchViaIntent(wmHelper)
+                    wmHelper.waitForFullScreenApp(testApp1.component)
+
+                    testApp2.launchViaIntent(wmHelper)
+                    wmHelper.waitForFullScreenApp(testApp2.component)
+
+                    // Swipe right from bottom to quick switch back
+                    // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
+                    // as to not accidentally trigger a swipe back or forward action which would result
+                    // in the same behavior but not testing quick swap.
+                    device.swipe(
+                            startDisplayBounds.bounds.right / 3,
+                            startDisplayBounds.bounds.bottom,
+                            2 * startDisplayBounds.bounds.right / 3,
+                            startDisplayBounds.bounds.bottom,
+                            if (testSpec.config.startRotation.isRotated()) 75 else 30
+                    )
+
+                    wmHelper.waitForFullScreenApp(testApp1.component)
+                    wmHelper.waitForAppTransitionIdle()
+                }
+            }
+            transitions {
+                // Swipe left from bottom to quick switch forward
+                // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
+                // as to not accidentally trigger a swipe back or forward action which would result
+                // in the same behavior but not testing quick swap.
+                device.swipe(
+                        2 * startDisplayBounds.bounds.right / 3,
+                        startDisplayBounds.bounds.bottom,
+                        startDisplayBounds.bounds.right / 3,
+                        startDisplayBounds.bounds.bottom,
+                        if (testSpec.config.startRotation.isRotated()) 75 else 30
+                )
+
+                wmHelper.waitForFullScreenApp(testApp2.component)
+                wmHelper.waitForAppTransitionIdle()
+            }
+
+            teardown {
+                test {
+                    testApp1.exit()
+                    testApp2.exit()
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks that the transition starts with [testApp1]'s windows filling/covering exactly the
+     * entirety of the display.
+     */
+    @Postsubmit
+    @Test
+    fun startsWithApp1WindowsCoverFullScreen() {
+        testSpec.assertWmStart {
+            this.frameRegion(testApp1.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with [testApp1]'s layers filling/covering exactly the
+     * entirety of the display.
+     */
+    @Postsubmit
+    @Test
+    fun startsWithApp1LayersCoverFullScreen() {
+        testSpec.assertLayersStart {
+            this.visibleRegion(testApp1.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with [testApp1] being the top window.
+     */
+    @Postsubmit
+    @Test
+    fun startsWithApp1WindowBeingOnTop() {
+        testSpec.assertWmStart {
+            this.isAppWindowOnTop(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp2] windows fill the entire screen (i.e. is "fullscreen") at the end of the
+     * transition once we have fully quick switched from [testApp1] back to the [testApp2].
+     */
+    @Postsubmit
+    @Test
+    fun endsWithApp2WindowsCoveringFullScreen() {
+        testSpec.assertWmEnd {
+            this.frameRegion(testApp2.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that [testApp2] layers fill the entire screen (i.e. is "fullscreen") at the end of the
+     * transition once we have fully quick switched from [testApp1] back to the [testApp2].
+     */
+    @Postsubmit
+    @Test
+    fun endsWithApp2LayersCoveringFullScreen() {
+        testSpec.assertLayersEnd {
+            this.visibleRegion(testApp2.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that [testApp2] is the top window at the end of the transition once we have fully quick
+     * switched from [testApp1] back to the [testApp2].
+     */
+    @Postsubmit
+    @Test
+    fun endsWithApp2BeingOnTop() {
+        testSpec.assertWmEnd {
+            this.isAppWindowOnTop(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp2]'s window starts off invisible and becomes visible at some point before
+     * the end of the transition and then stays visible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app2WindowBecomesAndStaysVisible() {
+        testSpec.assertWm {
+            this.isAppWindowInvisible(testApp2.component)
+                    .then()
+                    .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(testApp2.component, ignoreActivity = true)
+        }
+    }
+
+    /**
+     * Checks that [testApp2]'s layer starts off invisible and becomes visible at some point before
+     * the end of the transition and then stays visible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app2LayerBecomesAndStaysVisible() {
+        testSpec.assertLayers {
+            this.isInvisible(testApp2.component)
+                    .then()
+                    .isVisible(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp1]'s window starts off visible and becomes invisible at some point before
+     * the end of the transition and then stays invisible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app1WindowBecomesAndStaysInvisible() {
+        testSpec.assertWm {
+            this.isAppWindowVisible(testApp1.component, ignoreActivity = true)
+                    .then()
+                    .isAppWindowInvisible(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp1]'s layer starts off visible and becomes invisible at some point before
+     * the end of the transition and then stays invisible until the end of the transition.
+     */
+    @Postsubmit
+    @Test
+    fun app1LayerBecomesAndStaysInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(testApp1.component)
+                    .then()
+                    .isInvisible(testApp1.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp1]'s window is visible at least until [testApp2]'s window is visible.
+     * Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially
+     * visible.
+     */
+    @Postsubmit
+    @Test
+    fun app2WindowIsVisibleOnceApp1WindowIsInvisible() {
+        testSpec.assertWm {
+            this.isAppWindowVisible(testApp1.component)
+                    .then()
+                    .isAppWindowVisible(LAUNCHER_COMPONENT, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that [testApp1]'s layer is visible at least until [testApp2]'s window is visible.
+     * Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially
+     * visible.
+     */
+    @Postsubmit
+    @Test
+    fun app2LayerIsVisibleOnceApp1LayerIsInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(testApp1.component)
+                    .then()
+                    .isVisible(LAUNCHER_COMPONENT, isOptional = true)
+                    .then()
+                    .isVisible(SNAPSHOT_COMPONENT, isOptional = true)
+                    .then()
+                    .isVisible(testApp2.component)
+        }
+    }
+
+    /**
+     * Checks that the navbar window is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
+
+    /**
+     * Checks that the navbar layer is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible()
+
+    /**
+     * Checks that the navbar is always in the right position and covers the expected region.
+     *
+     * NOTE: This doesn't check that the navbar is visible or not.
+     */
+    @Postsubmit
+    @Test
+    fun navbarIsAlwaysInRightPosition() =
+            testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+
+    /**
+     * Checks that the status bar window is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
+
+    /**
+     * Checks that the status bar layer is visible throughout the entire transition.
+     */
+    @Postsubmit
+    @Test
+    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
+
+    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, Surface.ROTATION_90)
+                    )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
new file mode 100644
index 0000000..b010d4c
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -0,0 +1,347 @@
+/*
+ * 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.quickswitch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.platform.app.InstrumentationRegistry
+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.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerIsVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching to last opened app from launcher
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchFromLauncherTest`
+ *
+ * Actions:
+ *     Launch an app
+ *     Navigate home to show launcher
+ *     Swipe right from the bottom of the screen to quick switch back to the app
+ *
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val testApp = SimpleAppHelper(instrumentation)
+    private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            setup {
+                eachRun {
+                    testApp.launchViaIntent(wmHelper)
+                    device.pressHome()
+                    wmHelper.waitForHomeActivityVisible()
+                    wmHelper.waitForWindowSurfaceDisappeared(testApp.component)
+                }
+            }
+            transitions {
+                // Swipe right from bottom to quick switch back
+                // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
+                // as to not accidentally trigger a swipe back or forward action which would result
+                // in the same behavior but not testing quick swap.
+                device.swipe(
+                        startDisplayBounds.bounds.right / 3,
+                        startDisplayBounds.bounds.bottom,
+                        2 * startDisplayBounds.bounds.right / 3,
+                        startDisplayBounds.bounds.bottom,
+                        50
+                )
+
+                wmHelper.waitForFullScreenApp(testApp.component)
+                wmHelper.waitForAppTransitionIdle()
+            }
+
+            teardown {
+                eachRun {
+                    testApp.exit()
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks that [testApp] windows fill the entire screen (i.e. is "fullscreen") at the end of the
+     * transition once we have fully quick switched from the launcher back to the [testApp].
+     */
+    @Presubmit
+    @Test
+    fun endsWithAppWindowsCoveringFullScreen() {
+        testSpec.assertWmEnd {
+            this.frameRegion(testApp.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that [testApp] layers fill the entire screen (i.e. is "fullscreen") at the end of the
+     * transition once we have fully quick switched from the launcher back to the [testApp].
+     */
+    @Presubmit
+    @Test
+    fun endsWithAppLayersCoveringFullScreen() {
+        testSpec.assertLayersEnd {
+            this.visibleRegion(testApp.component).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that [testApp] is the top window at the end of the transition once we have fully quick
+     * switched from the launcher back to the [testApp].
+     */
+    @Presubmit
+    @Test
+    fun endsWithAppBeingOnTop() {
+        testSpec.assertWmEnd {
+            this.isAppWindowOnTop(testApp.component)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with the home activity being tagged as visible.
+     */
+    @Presubmit
+    @Test
+    fun startsWithHomeActivityFlaggedVisible() {
+        testSpec.assertWmStart {
+            this.isHomeActivityVisible(true)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with the launcher windows filling/covering exactly the
+     * entirety of the display.
+     */
+    @Presubmit
+    @Test
+    fun startsWithLauncherWindowsCoverFullScreen() {
+        testSpec.assertWmStart {
+            this.frameRegion(LAUNCHER_COMPONENT).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with the launcher layers filling/covering exactly the
+     * entirety of the display.
+     */
+    @Presubmit
+    @Test
+    fun startsWithLauncherLayersCoverFullScreen() {
+        testSpec.assertLayersStart {
+            this.visibleRegion(LAUNCHER_COMPONENT).coversExactly(startDisplayBounds)
+        }
+    }
+
+    /**
+     * Checks that the transition starts with the launcher being the top window.
+     */
+    @Presubmit
+    @Test
+    fun startsWithLauncherBeingOnTop() {
+        testSpec.assertWmStart {
+            this.isAppWindowOnTop(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks that the transition ends with the home activity being flagged as not visible. By this
+     * point we should have quick switched away from the launcher back to the [testApp].
+     */
+    @Presubmit
+    @Test
+    fun endsWithHomeActivityFlaggedInvisible() {
+        testSpec.assertWmEnd {
+            this.isHomeActivityVisible(false)
+        }
+    }
+
+    /**
+     * Checks that [testApp]'s window starts off invisible and becomes visible at some point before
+     * the end of the transition and then stays visible until the end of the transition.
+     */
+    @Presubmit
+    @Test
+    fun appWindowBecomesAndStaysVisible() {
+        testSpec.assertWm {
+            this.isAppWindowInvisible(testApp.component, ignoreActivity = true)
+                    .then()
+                    .isAppWindowVisible(testApp.component, ignoreActivity = true)
+        }
+    }
+
+    /**
+     * Checks that [testApp]'s layer starts off invisible and becomes visible at some point before
+     * the end of the transition and then stays visible until the end of the transition.
+     */
+    @Presubmit
+    @Test
+    fun appLayerBecomesAndStaysVisible() {
+        testSpec.assertLayers {
+            this.isInvisible(testApp.component)
+                    .then()
+                    .isVisible(testApp.component)
+        }
+    }
+
+    /**
+     * Checks that the launcher window starts off visible and becomes invisible at some point before
+     * the end of the transition and then stays invisible until the end of the transition.
+     */
+    @Presubmit
+    @Test
+    fun launcherWindowBecomesAndStaysInvisible() {
+        testSpec.assertWm {
+            this.isAppWindowVisible(LAUNCHER_COMPONENT)
+                    .then()
+                    .isAppWindowInvisible(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks that the launcher layer starts off visible and becomes invisible at some point before
+     * the end of the transition and then stays invisible until the end of the transition.
+     */
+    @Presubmit
+    @Test
+    fun launcherLayerBecomesAndStaysInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(LAUNCHER_COMPONENT)
+                    .then()
+                    .isInvisible(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks that the launcher window is visible at least until the app window is visible. Ensures
+     * that at any point, either the launcher or [testApp] windows are at least partially visible.
+     */
+    @Presubmit
+    @Test
+    fun appWindowIsVisibleOnceLauncherWindowIsInvisible() {
+        testSpec.assertWm {
+            this.isAppWindowVisible(LAUNCHER_COMPONENT)
+                    .then()
+                    .isAppWindowVisible(SNAPSHOT_COMPONENT)
+                    .then()
+                    .isAppWindowVisible(testApp.component)
+        }
+    }
+
+    /**
+     * Checks that the launcher layer is visible at least until the app layer is visible. Ensures
+     * that at any point, either the launcher or [testApp] layers are at least partially visible.
+     */
+    @Presubmit
+    @Test
+    fun appLayerIsVisibleOnceLauncherLayerIsInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(LAUNCHER_COMPONENT)
+                    .then()
+                    .isVisible(SNAPSHOT_COMPONENT)
+                    .then()
+                    .isVisible(testApp.component)
+        }
+    }
+
+    /**
+     * Checks that the navbar window is visible throughout the entire transition.
+     */
+    @Presubmit
+    @Test
+    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
+
+    /**
+     * Checks that the navbar layer is visible throughout the entire transition.
+     */
+    @Presubmit
+    @Test
+    fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible()
+
+    /**
+     * Checks that the navbar is always in the right position and covers the expected region.
+     *
+     * NOTE: This doesn't check that the navbar is visible or not.
+     */
+    @Presubmit
+    @Test
+    fun navbarIsAlwaysInRightPosition() =
+            testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+
+    /**
+     * Checks that the status bar window is visible throughout the entire transition.
+     */
+    @Presubmit
+    @Test
+    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
+
+    /**
+     * Checks that the status bar layer is visible throughout the entire transition.
+     */
+    @Presubmit
+    @Test
+    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
+
+    /**
+     * Checks that the screen is always fully covered by visible layers throughout the transition.
+     */
+    @Presubmit
+    @Test
+    fun screenIsAlwaysFilled() = testSpec.entireScreenCovered()
+
+    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
+                            ),
+                            // TODO: Test with 90 rotation
+                            supportedRotations = listOf(Surface.ROTATION_0)
+                    )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 73986b6..33ddd00 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.rotation
 
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -85,7 +84,7 @@
         testSpec.statusBarWindowIsVisible()
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarLayerIsVisible() {
         testSpec.statusBarLayerIsVisible()
@@ -98,29 +97,16 @@
             testSpec.config.startRotation, testSpec.config.endRotation)
     }
 
-    @Presubmit
-    @Test
-    override fun navBarWindowIsVisible() {
-        super.navBarWindowIsVisible()
-    }
-
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisible() {
-        super.navBarLayerIsVisible()
-    }
-
     @FlakyTest
     @Test
     override fun navBarLayerRotatesAndScales() {
         super.navBarLayerRotatesAndScales()
     }
 
-    @Postsubmit
+    @FlakyTest
     @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
-    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 2b0b3c2..612ff9d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -25,7 +25,6 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -39,8 +38,6 @@
     protected abstract val testApp: StandardAppHelper
 
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
-    protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
 
     protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
         setup {
@@ -107,10 +104,7 @@
 
     @Presubmit
     @Test
-    open fun entireScreenCovered() {
-        testSpec.entireScreenCovered(testSpec.config.startRotation,
-            testSpec.config.endRotation, allStates = false)
-    }
+    open fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     @Presubmit
     @Test
@@ -124,7 +118,9 @@
     @Test
     open fun appLayerRotates_StartingPos() {
         testSpec.assertLayersStart {
-            this.visibleRegion(testApp.component).coversExactly(startingPos)
+            this.entry.displays.map { display ->
+                this.visibleRegion(testApp.component).coversExactly(display.layerStackSpace)
+            }
         }
     }
 
@@ -132,7 +128,9 @@
     @Test
     open fun appLayerRotates_EndingPos() {
         testSpec.assertLayersEnd {
-            this.visibleRegion(testApp.component).coversExactly(endingPos)
+            this.entry.displays.map { display ->
+                this.visibleRegion(testApp.component).coversExactly(display.layerStackSpace)
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index b97b977..48efe73 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.rotation
 
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManager
 import androidx.test.filters.FlakyTest
@@ -99,13 +98,15 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun appLayerRotates() {
         testSpec.assertLayers {
-            this.coversExactly(startingPos, testApp.component)
-                .then()
-                .coversExactly(endingPos, testApp.component)
+            this.invoke("entireScreenCovered") { entry ->
+                entry.entry.displays.map { display ->
+                    entry.visibleRegion(testApp.component).coversExactly(display.layerStackSpace)
+                }
+            }
         }
     }
 
@@ -125,24 +126,6 @@
         }
     }
 
-    @Presubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-    }
-
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsVisible() {
-        super.navBarWindowIsVisible()
-    }
-
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisible() {
-        super.navBarLayerIsVisible()
-    }
-
     @FlakyTest
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index 4da3eca..3eeba7d 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -70,7 +70,45 @@
     }
 
     @Test
-    fun testGestureMonitorAnr() {
+    fun testGestureMonitorAnr_Close() {
+        triggerAnr()
+        clickCloseAppOnAnrDialog()
+    }
+
+    @Test
+    fun testGestureMonitorAnr_Wait() {
+        triggerAnr()
+        clickWaitOnAnrDialog()
+        SystemClock.sleep(500) // Wait at least 500ms after tapping on wait
+        // ANR dialog should reappear after a delay - find the close button on it to verify
+        clickCloseAppOnAnrDialog()
+    }
+
+    private fun clickCloseAppOnAnrDialog() {
+        // Find anr dialog and kill app
+        val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+        val closeAppButton: UiObject2? =
+                uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+        if (closeAppButton == null) {
+            fail("Could not find anr dialog")
+            return
+        }
+        closeAppButton.click()
+    }
+
+    private fun clickWaitOnAnrDialog() {
+        // Find anr dialog and tap on wait
+        val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+        val waitButton: UiObject2? =
+                uiDevice.wait(Until.findObject(By.res("android:id/aerr_wait")), 20000)
+        if (waitButton == null) {
+            fail("Could not find anr dialog/wait button")
+            return
+        }
+        waitButton.click()
+    }
+
+    private fun triggerAnr() {
         startUnresponsiveActivity()
         val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
         val obj: UiObject2? = uiDevice.wait(Until.findObject(
@@ -91,20 +129,6 @@
 
         // Todo: replace using timeout from android.hardware.input.IInputManager
         SystemClock.sleep(5000) // default ANR timeout for gesture monitors
-
-        clickCloseAppOnAnrDialog()
-    }
-
-    private fun clickCloseAppOnAnrDialog() {
-        // Find anr dialog and kill app
-        val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
-        val closeAppButton: UiObject2? =
-                uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
-        if (closeAppButton == null) {
-            fail("Could not find anr dialog")
-            return
-        }
-        closeAppButton.click()
     }
 
     private fun startUnresponsiveActivity() {
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/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
index e956be3..dd9b294 100644
--- a/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
+++ b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
@@ -82,11 +82,10 @@
 
         long elapsedTimeNs = 0;
         while (benchmarkState.keepRunning(elapsedTimeNs)) {
-            sJobStore.clear();
+            sJobStore.clearForTesting();
             for (JobStatus job : jobList) {
-                sJobStore.add(job);
+                sJobStore.addForTesting(job);
             }
-            sJobStore.waitForWriteToCompleteForTesting(10_000);
 
             final long startTime = SystemClock.elapsedRealtimeNanos();
             sJobStore.writeStatusToDiskForTesting();
@@ -110,11 +109,11 @@
 
         long elapsedTimeNs = 0;
         while (benchmarkState.keepRunning(elapsedTimeNs)) {
-            sJobStore.clear();
+            sJobStore.clearForTesting();
             for (JobStatus job : jobList) {
-                sJobStore.add(job);
+                sJobStore.addForTesting(job);
             }
-            sJobStore.waitForWriteToCompleteForTesting(10_000);
+            sJobStore.writeStatusToDiskForTesting();
 
             JobSet jobSet = new JobSet();
 
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 05c46ed..7a668a5 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -54,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;
@@ -203,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
@@ -739,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")
     /**
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..a283aa9 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -293,50 +293,6 @@
     }
 
     @Test
-    public void testRollbackDataPolicy_Phase1_Install() throws Exception {
-        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).setStaged()
-                .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
-        Install b2 = Install.single(TestApp.B2).setStaged()
-                .setEnableRollback(PackageManager.RollbackDataPolicy.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();
-    }
-
-    @Test
-    public void testRollbackDataPolicy_Phase2_Rollback() throws Exception {
-        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-        assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-        // 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());
-    }
-
-    @Test
-    public void testRollbackDataPolicy_Phase3_VerifyRollback() throws Exception {
-        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-        assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-        assertThat(InstallUtils.getInstalledVersion(TestApp.C)).isEqualTo(1);
-        // 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);
-    }
-
-    @Test
     public void expireRollbacks() throws Exception {
         // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
         // committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 1aa5c24..1c2f244 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -267,25 +267,6 @@
         runPhase("testRollbackAllowlistedApp_Phase2_VerifyInstall");
     }
 
-    @Test
-    public void testRollbackDataPolicy() throws Exception {
-        List<String> before = getSnapshotDirectories("/data/misc_ce/0/rollback");
-
-        runPhase("testRollbackDataPolicy_Phase1_Install");
-        getDevice().reboot();
-        runPhase("testRollbackDataPolicy_Phase2_Rollback");
-        getDevice().reboot();
-        runPhase("testRollbackDataPolicy_Phase3_VerifyRollback");
-
-        // Verify snapshots are deleted after restoration
-        List<String> after = getSnapshotDirectories("/data/misc_ce/0/rollback");
-        // Only check directories newly created during the test
-        after.removeAll(before);
-        // There should be only one /data/misc_ce/0/rollback/<rollbackId> created during test
-        assertThat(after).hasSize(1);
-        assertDirectoryIsEmpty(after.get(0));
-    }
-
     /**
      * Tests that userdata of apk-in-apex is restored when apex is rolled back.
      */
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index cac14a7..558798d 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -37,6 +37,7 @@
         ":test.rebootless_apex_v1",
         ":test.rebootless_apex_v2",
     ],
+    platform_apis: true,
 }
 
 java_test_host {
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 4684f01..c610641 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -17,16 +17,27 @@
 package com.android.tests.stagedinstallinternal;
 
 import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
+import static com.android.cts.install.lib.InstallUtils.waitForSessionReady;
 import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
 import android.Manifest;
+import android.content.pm.ApexStagedEvent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
+import android.content.pm.StagedApexInfo;
+import android.os.IBinder;
+import android.os.ServiceManager;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -39,6 +50,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
@@ -401,9 +414,73 @@
                 AssertionError.class,
                 "Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
                 Install.single(APEX_V2));
-
     }
 
+    @Test
+    public void testGetStagedModuleNames() throws Exception {
+        // Before staging a session
+        String[] result = getPackageManagerNative().getStagedApexModuleNames();
+        assertThat(result).hasLength(0);
+        // Stage an apex
+        int sessionId = Install.single(APEX_V2).setStaged().commit();
+        waitForSessionReady(sessionId);
+        result = getPackageManagerNative().getStagedApexModuleNames();
+        assertThat(result).hasLength(1);
+        assertThat(result).isEqualTo(new String[]{SHIM_APEX_PACKAGE_NAME});
+        // Abandon the session
+        InstallUtils.openPackageInstallerSession(sessionId).abandon();
+        result = getPackageManagerNative().getStagedApexModuleNames();
+        assertThat(result).hasLength(0);
+    }
+
+    @Test
+    public void testGetStagedApexInfo() throws Exception {
+        // Ask for non-existing module
+        StagedApexInfo result = getPackageManagerNative().getStagedApexInfo("not found");
+        assertThat(result).isNull();
+        // Stage an apex
+        int sessionId = Install.single(APEX_V2).setStaged().commit();
+        waitForSessionReady(sessionId);
+        // Query proper module name
+        result = getPackageManagerNative().getStagedApexInfo(SHIM_APEX_PACKAGE_NAME);
+        assertThat(result.moduleName).isEqualTo(SHIM_APEX_PACKAGE_NAME);
+        InstallUtils.openPackageInstallerSession(sessionId).abandon();
+    }
+
+    public static class MockStagedApexObserver extends IStagedApexObserver.Stub {
+        @Override
+        public void onApexStaged(ApexStagedEvent event) {
+            assertThat(event).isNotNull();
+        }
+    }
+
+    @Test
+    public void testStagedApexObserver() throws Exception {
+        MockStagedApexObserver realObserver = new MockStagedApexObserver();
+        IStagedApexObserver observer = spy(realObserver);
+        assertThat(observer).isNotNull();
+        getPackageManagerNative().registerStagedApexObserver(observer);
+
+        // Stage an apex and verify observer was called
+        int sessionId = Install.single(APEX_V2).setStaged().commit();
+        waitForSessionReady(sessionId);
+        ArgumentCaptor<ApexStagedEvent> captor = ArgumentCaptor.forClass(ApexStagedEvent.class);
+        verify(observer, timeout(5000)).onApexStaged(captor.capture());
+        assertThat(captor.getValue().stagedApexModuleNames).isEqualTo(
+                new String[] {SHIM_APEX_PACKAGE_NAME});
+
+        // Abandon and verify observer is called
+        Mockito.clearInvocations(observer);
+        InstallUtils.openPackageInstallerSession(sessionId).abandon();
+        verify(observer, timeout(5000)).onApexStaged(captor.capture());
+        assertThat(captor.getValue().stagedApexModuleNames).hasLength(0);
+    }
+
+    private IPackageManagerNative getPackageManagerNative() {
+        IBinder binder = ServiceManager.waitForService("package_native");
+        assertThat(binder).isNotNull();
+        return IPackageManagerNative.Stub.asInterface(binder);
+    }
     private static void assertSessionApplied(int sessionId) {
         assertSessionState(sessionId, (session) -> {
             assertThat(session.isStagedSessionApplied()).isTrue();
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 5021009..3102103 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -478,6 +478,21 @@
         runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
     }
 
+    @Test
+    public void testGetStagedModuleNames() throws Exception {
+        runPhase("testGetStagedModuleNames");
+    }
+
+    @Test
+    public void testGetStagedApexInfo() throws Exception {
+        runPhase("testGetStagedApexInfo");
+    }
+
+    @Test
+    public void testStagedApexObserver() throws Exception {
+        runPhase("testStagedApexObserver");
+    }
+
     private List<String> getStagingDirectories() throws DeviceNotAvailableException {
         String baseDir = "/data/app-staging";
         try {
diff --git a/tests/componentalias/Android.bp b/tests/componentalias/Android.bp
new file mode 100644
index 0000000..4e2009d
--- /dev/null
+++ b/tests/componentalias/Android.bp
@@ -0,0 +1,86 @@
+// 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: ["Android-Apache-2.0"],
+}
+
+java_defaults {
+    name: "ComponentAliasTests_defaults",
+    static_libs: [
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "mockito-target-extended-minus-junit4",
+        "truth-prebuilt",
+        "ub-uiautomator",
+    ],
+    libs: ["android.test.base"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+    platform_apis: true, // We use hidden APIs in the test.
+}
+
+// We build three APKs from the exact same source files, so these APKs contain the exact same tests.
+// And we run the tests on each APK, so that we can test various situations:
+// - When the alias is in the same package, target in the same package.
+// - When the alias is in the same package, target in another package.
+// - When the alias is in another package, which also contains the target.
+// - When the alias is in another package, and the target is in yet another package.
+// etc etc...
+
+android_test {
+    name: "ComponentAliasTests",
+    defaults: [
+        "ComponentAliasTests_defaults",
+    ],
+    package_name: "android.content.componentalias.tests",
+    manifest: "AndroidManifest.xml",
+    additional_manifests: [
+        "AndroidManifest_service_aliases.xml",
+        "AndroidManifest_service_targets.xml",
+    ],
+    test_config_template: "AndroidTest-template.xml",
+}
+
+android_test {
+    name: "ComponentAliasTests1",
+    defaults: [
+        "ComponentAliasTests_defaults",
+    ],
+    package_name: "android.content.componentalias.tests.sub1",
+    manifest: "AndroidManifest.xml",
+    additional_manifests: [
+        "AndroidManifest_service_aliases.xml",
+        "AndroidManifest_service_targets.xml",
+    ],
+    test_config_template: "AndroidTest-template.xml",
+}
+
+android_test {
+    name: "ComponentAliasTests2",
+    defaults: [
+        "ComponentAliasTests_defaults",
+    ],
+    package_name: "android.content.componentalias.tests.sub2",
+    manifest: "AndroidManifest.xml",
+    additional_manifests: [
+        "AndroidManifest_service_aliases.xml",
+        "AndroidManifest_service_targets.xml",
+    ],
+    test_config_template: "AndroidTest-template.xml",
+}
diff --git a/tests/componentalias/AndroidManifest.xml b/tests/componentalias/AndroidManifest.xml
new file mode 100755
index 0000000..893be8e
--- /dev/null
+++ b/tests/componentalias/AndroidManifest.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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.content.componentalias.tests" >
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.content.componentalias.tests" >
+    </instrumentation>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_service_aliases.xml b/tests/componentalias/AndroidManifest_service_aliases.xml
new file mode 100644
index 0000000..28ac2a5
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_service_aliases.xml
@@ -0,0 +1,50 @@
+<?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="android.content.componentalias.tests" >
+    <application>
+        <!--
+            Note the alias components are essentially just placeholders, so the APKs don't have to
+            have the implementation classes.
+        -->
+        <service android:name=".s.Alias00" android:exported="true" android:enabled="true" >
+            <meta-data android:name="alias_target" android:value="android.content.componentalias.tests/android.content.componentalias.tests.s.Target00" />
+            <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+            <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_00" /></intent-filter>
+        </service>
+        <service android:name=".s.Alias01" android:exported="true" android:enabled="true" >
+            <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub1/android.content.componentalias.tests.s.Target01" />
+            <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+            <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_01" /></intent-filter>
+        </service>
+        <service android:name=".s.Alias02" android:exported="true" android:enabled="true" >
+            <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub2/android.content.componentalias.tests.s.Target02" />
+            <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+            <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_02" /></intent-filter>
+        </service>
+        <service android:name=".s.Alias03" android:exported="true" android:enabled="true" >
+            <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub1/android.content.componentalias.tests.s.Target03" />
+            <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+            <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_03" /></intent-filter>
+        </service>
+        <service android:name=".s.Alias04" android:exported="true" android:enabled="true" >
+            <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub2/android.content.componentalias.tests.s.Target04" />
+            <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+            <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_04" /></intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_service_targets.xml b/tests/componentalias/AndroidManifest_service_targets.xml
new file mode 100644
index 0000000..6e7228c
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_service_targets.xml
@@ -0,0 +1,31 @@
+<?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="android.content.componentalias.tests" >
+    <application>
+        <service android:name=".s.Target00" android:exported="true" android:enabled="true" >
+        </service>
+        <service android:name=".s.Target01" android:exported="true" android:enabled="true" >
+        </service>
+        <service android:name=".s.Target02" android:exported="true" android:enabled="true" >
+        </service>
+        <service android:name=".s.Target03" android:exported="true" android:enabled="true" >
+        </service>
+        <service android:name=".s.Target04" android:exported="true" android:enabled="true" >
+        </service>
+    </application>
+</manifest>
diff --git a/tests/componentalias/AndroidTest-template.xml b/tests/componentalias/AndroidTest-template.xml
new file mode 100644
index 0000000..afdfe79
--- /dev/null
+++ b/tests/componentalias/AndroidTest-template.xml
@@ -0,0 +1,38 @@
+<?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>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="ComponentAliasTests.apk" />
+        <option name="test-file-name" value="ComponentAliasTests1.apk" />
+        <option name="test-file-name" value="ComponentAliasTests2.apk" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <!-- Exempt the helper APKs from the BG restriction, so they can start BG services. -->
+        <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests" />
+        <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub1" />
+        <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub2" />
+
+        <option name="teardown-command" value="cmd deviceidle whitelist -android.content.componentalias.tests" />
+        <option name="teardown-command" value="cmd deviceidle whitelist -android.content.componentalias.tests.sub1" />
+        <option name="teardown-command" value="cmd deviceidle whitelist -android.content.componentalias.tests.sub2" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="{PACKAGE}" />
+        <option name="runtime-hint" value="2m" />
+        <option name="isolated-storage" value="false" />
+    </test>
+</configuration>
diff --git a/tests/componentalias/OWNERS b/tests/componentalias/OWNERS
new file mode 100644
index 0000000..1073c81
--- /dev/null
+++ b/tests/componentalias/OWNERS
@@ -0,0 +1,2 @@
+omakoto@google.com
+yamasani@google.com
\ No newline at end of file
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
new file mode 100644
index 0000000..d41696f
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
@@ -0,0 +1,215 @@
+/*
+ * 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.componentalias.tests;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Parcelabe containing a "message" that's meant to be delivered via BroadcastMessenger.
+ *
+ * To add a new field, just add a private member field, and run:
+ * codegen $ANDROID_BUILD_TOP/frameworks/base/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
+ */
+@DataClass(
+        genConstructor = false,
+        genSetters = true,
+        genToString = true,
+        genAidl = false)
+public final class ComponentAliasMessage implements Parcelable {
+    public ComponentAliasMessage() {
+    }
+
+    @Nullable
+    private String mMessage;
+
+    @Nullable
+    private String mMethodName;
+
+    @Nullable
+    private String mSenderIdentity;
+
+    @Nullable
+    private Intent mIntent;
+
+    @Nullable
+    private ComponentName mComponent;
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.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 getMessage() {
+        return mMessage;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getMethodName() {
+        return mMethodName;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getSenderIdentity() {
+        return mSenderIdentity;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable Intent getIntent() {
+        return mIntent;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable ComponentName getComponent() {
+        return mComponent;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull ComponentAliasMessage setMessage(@NonNull String value) {
+        mMessage = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull ComponentAliasMessage setMethodName(@NonNull String value) {
+        mMethodName = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull ComponentAliasMessage setSenderIdentity(@NonNull String value) {
+        mSenderIdentity = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull ComponentAliasMessage setIntent(@NonNull Intent value) {
+        mIntent = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull ComponentAliasMessage setComponent(@NonNull ComponentName value) {
+        mComponent = value;
+        return this;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ComponentAliasMessage { " +
+                "message = " + mMessage + ", " +
+                "methodName = " + mMethodName + ", " +
+                "senderIdentity = " + mSenderIdentity + ", " +
+                "intent = " + mIntent + ", " +
+                "component = " + mComponent +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mMessage != null) flg |= 0x1;
+        if (mMethodName != null) flg |= 0x2;
+        if (mSenderIdentity != null) flg |= 0x4;
+        if (mIntent != null) flg |= 0x8;
+        if (mComponent != null) flg |= 0x10;
+        dest.writeByte(flg);
+        if (mMessage != null) dest.writeString(mMessage);
+        if (mMethodName != null) dest.writeString(mMethodName);
+        if (mSenderIdentity != null) dest.writeString(mSenderIdentity);
+        if (mIntent != null) dest.writeTypedObject(mIntent, flags);
+        if (mComponent != null) dest.writeTypedObject(mComponent, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ComponentAliasMessage(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        String message = (flg & 0x1) == 0 ? null : in.readString();
+        String methodName = (flg & 0x2) == 0 ? null : in.readString();
+        String senderIdentity = (flg & 0x4) == 0 ? null : in.readString();
+        Intent intent = (flg & 0x8) == 0 ? null : (Intent) in.readTypedObject(Intent.CREATOR);
+        ComponentName component = (flg & 0x10) == 0 ? null : (ComponentName) in.readTypedObject(ComponentName.CREATOR);
+
+        this.mMessage = message;
+        this.mMethodName = methodName;
+        this.mSenderIdentity = senderIdentity;
+        this.mIntent = intent;
+        this.mComponent = component;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ComponentAliasMessage> CREATOR
+            = new Parcelable.Creator<ComponentAliasMessage>() {
+        @Override
+        public ComponentAliasMessage[] newArray(int size) {
+            return new ComponentAliasMessage[size];
+        }
+
+        @Override
+        public ComponentAliasMessage createFromParcel(@NonNull Parcel in) {
+            return new ComponentAliasMessage(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1630098801203L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java",
+            inputSignatures = "private @android.annotation.Nullable java.lang.String mMessage\nprivate @android.annotation.Nullable java.lang.String mMethodName\nprivate @android.annotation.Nullable java.lang.String mSenderIdentity\nprivate @android.annotation.Nullable android.content.Intent mIntent\nprivate @android.annotation.Nullable android.content.ComponentName mComponent\nclass ComponentAliasMessage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true, genToString=true, genAidl=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java
new file mode 100644
index 0000000..af51c32
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java
@@ -0,0 +1,359 @@
+/*
+ * 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.componentalias.tests;
+
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.MAIN_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.SUB1_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.SUB2_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.TAG;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.core.IsNot.not;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.provider.DeviceConfig;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.BroadcastMessenger;
+import com.android.compatibility.common.util.BroadcastMessenger.Receiver;
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.function.Consumer;
+
+/**
+ * Test for the experimental "Component alias" feature.
+ *
+ * Note this test exercises the relevant APIs, but don't actually check if the aliases are
+ * resolved.
+ *
+ * Note all the helper APKs are battery-exempted (via AndroidTest.xml), so they can run
+ * BG services.
+ */
+public class ComponentAliasServiceTest {
+
+    private static final Context sContext = InstrumentationRegistry.getTargetContext();
+
+    private static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+    @Before
+    public void enableComponentAlias() throws Exception {
+        sDeviceConfig.set("component_alias_overrides", "");
+        sDeviceConfig.set("enable_experimental_component_alias", "true");
+
+        // Device config propagation happens on a handler, so we need to wait for AM to
+        // actually set it.
+        TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+            return ShellUtils.runShellCommand("dumpsys activity component-alias")
+                    .indexOf("Enabled: true") > 0;
+        });
+    }
+
+    @AfterClass
+    public static void restoreDeviceConfig() throws Exception {
+        sDeviceConfig.close();
+    }
+
+    /**
+     * Service connection used throughout the tests. It sends a message for each callback via
+     * the messenger.
+     */
+    private static final ServiceConnection sServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.w(TAG, "onServiceConnected: " + name);
+
+            ComponentAliasMessage m = new ComponentAliasMessage()
+                    .setSenderIdentity("sServiceConnection")
+                    .setMethodName("onServiceConnected")
+                    .setComponent(name);
+
+            BroadcastMessenger.send(sContext, TAG, m);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.w(TAG, "onServiceDisconnected: " + name);
+
+            ComponentAliasMessage m = new ComponentAliasMessage()
+                    .setSenderIdentity("sServiceConnection")
+                    .setMethodName("onServiceDisconnected")
+                    .setComponent(name);
+
+            BroadcastMessenger.send(sContext, TAG, m);
+        }
+
+        @Override
+        public void onBindingDied(ComponentName name) {
+            Log.w(TAG, "onBindingDied: " + name);
+
+            ComponentAliasMessage m = new ComponentAliasMessage()
+                    .setSenderIdentity("sServiceConnection")
+                    .setMethodName("onBindingDied");
+
+            BroadcastMessenger.send(sContext, TAG, m);
+        }
+
+        @Override
+        public void onNullBinding(ComponentName name) {
+            Log.w(TAG, "onNullBinding: " + name);
+
+            ComponentAliasMessage m = new ComponentAliasMessage()
+                    .setSenderIdentity("sServiceConnection")
+                    .setMethodName("onNullBinding");
+
+            BroadcastMessenger.send(sContext, TAG, m);
+        }
+    };
+
+    private void testStartAndStopService_common(
+            Intent originalIntent,
+            ComponentName componentNameForClient,
+            ComponentName componentNameForTarget) {
+
+        ComponentAliasMessage m;
+
+        try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+            // Start the service.
+            ComponentName result = sContext.startService(originalIntent);
+            assertThat(result).isEqualTo(componentNameForClient);
+
+            // Check
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onStartCommand");
+            // The app sees the rewritten intent.
+            assertThat(m.getIntent().getComponent()).isEqualTo(componentNameForTarget);
+
+            // Verify the original intent.
+            assertThat(m.getIntent().getOriginalIntent().getComponent())
+                    .isEqualTo(originalIntent.getComponent());
+            assertThat(m.getIntent().getOriginalIntent().getPackage())
+                    .isEqualTo(originalIntent.getPackage());
+
+            // Stop the service.
+            sContext.stopService(originalIntent);
+
+            // Check
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onDestroy");
+
+            receiver.ensureNoMoreMessages();
+        }
+    }
+
+    private static class Combo {
+        public final ComponentName alias;
+        public final ComponentName target;
+        public final String action;
+
+        private Combo(ComponentName alias, ComponentName target, String action) {
+            this.alias = alias;
+            this.target = target;
+            this.action = action;
+        }
+    }
+
+    private void forEachCombo(Consumer<Combo> callback) {
+        callback.accept(new Combo(
+                new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias00"),
+                new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Target00"),
+                MAIN_PACKAGE + ".IS_ALIAS_00"));
+        callback.accept(new Combo(
+                new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias01"),
+                new ComponentName(SUB1_PACKAGE, MAIN_PACKAGE + ".s.Target01"),
+                MAIN_PACKAGE + ".IS_ALIAS_01"));
+        callback.accept(new Combo(
+                new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias02"),
+                new ComponentName(SUB2_PACKAGE, MAIN_PACKAGE + ".s.Target02"),
+                MAIN_PACKAGE + ".IS_ALIAS_02"));
+    }
+
+
+    @Test
+    public void testStartAndStopService_explicitComponentName() throws Exception {
+        forEachCombo((c) -> {
+            Intent i = new Intent().setComponent(c.alias);
+            testStartAndStopService_common(i, c.alias, c.target);
+        });
+    }
+
+    @Test
+    public void testStartAndStopService_explicitPackageName() throws Exception {
+        forEachCombo((c) -> {
+            Intent i = new Intent().setPackage(c.alias.getPackageName());
+            i.setAction(c.action);
+
+            testStartAndStopService_common(i, c.alias, c.target);
+        });
+    }
+
+    @Test
+    public void testStartAndStopService_override() throws Exception {
+        Intent i = new Intent().setPackage(MAIN_PACKAGE);
+        i.setAction(MAIN_PACKAGE + ".IS_ALIAS_01");
+
+        // Change some of the aliases from what's defined in <meta-data>.
+
+        ComponentName aliasA = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias01");
+        ComponentName targetA = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Target02");
+
+        ComponentName aliasB = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias02");
+        ComponentName targetB = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Target01");
+
+        sDeviceConfig.set("component_alias_overrides",
+                aliasA.flattenToShortString() + ":" + targetA.flattenToShortString()
+                + ","
+                + aliasB.flattenToShortString() + ":" + targetB.flattenToShortString());
+
+        TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+            return ShellUtils.runShellCommand("dumpsys activity component-alias")
+                    .indexOf(aliasA.flattenToShortString()
+                            + " -> " + targetA.flattenToShortString()) > 0;
+        });
+
+
+        testStartAndStopService_common(i, aliasA, targetA);
+    }
+
+    private void testBindAndUnbindService_common(
+            Intent originalIntent,
+            ComponentName componentNameForClient,
+            ComponentName componentNameForTarget) {
+        ComponentAliasMessage m;
+
+        try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+            // Bind to the service.
+            assertThat(sContext.bindService(
+                    originalIntent, sServiceConnection, BIND_AUTO_CREATE)).isTrue();
+
+            // Check the target side behavior.
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onBind");
+            // The app sees the rewritten intent.
+            assertThat(m.getIntent().getComponent()).isEqualTo(componentNameForTarget);
+
+            // Verify the original intent.
+            assertThat(m.getIntent().getOriginalIntent().getComponent())
+                    .isEqualTo(originalIntent.getComponent());
+            assertThat(m.getIntent().getOriginalIntent().getPackage())
+                    .isEqualTo(originalIntent.getPackage());
+
+            // Check the client side behavior.
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onServiceConnected");
+            // The app sees the rewritten intent.
+            assertThat(m.getComponent()).isEqualTo(componentNameForClient);
+
+            // Unbind.
+            sContext.unbindService(sServiceConnection);
+
+            // Check the target side behavior.
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onDestroy");
+
+            // Note onServiceDisconnected() won't be called in this case.
+            receiver.ensureNoMoreMessages();
+        }
+    }
+
+    @Test
+    public void testBindService_explicitComponentName() throws Exception {
+        forEachCombo((c) -> {
+            Intent i = new Intent().setComponent(c.alias);
+
+            testBindAndUnbindService_common(i, c.alias, c.target);
+        });
+
+    }
+
+    @Test
+    public void testBindService_explicitPackageName() throws Exception {
+        forEachCombo((c) -> {
+            Intent i = new Intent().setPackage(c.alias.getPackageName());
+            i.setAction(c.action);
+
+            testBindAndUnbindService_common(i, c.alias, c.target);
+        });
+    }
+
+    /**
+     * Make sure, when the service process is killed, the client will get a callback with the
+     * right component name.
+     */
+    @Test
+    public void testBindService_serviceKilled() throws Exception {
+
+        // We need to kill SUB2_PACKAGE, don't run it for this package.
+        Assume.assumeThat(sContext.getPackageName(), not(SUB2_PACKAGE));
+
+        Intent originalIntent = new Intent().setPackage(MAIN_PACKAGE);
+        originalIntent.setAction(MAIN_PACKAGE + ".IS_ALIAS_02");
+
+        final ComponentName componentNameForClient =
+                new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias02");
+        final ComponentName componentNameForTarget =
+                new ComponentName(SUB2_PACKAGE, MAIN_PACKAGE + ".s.Target02");
+
+        ComponentAliasMessage m;
+
+        try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+            // Bind to the service.
+            assertThat(sContext.bindService(
+                    originalIntent, sServiceConnection, BIND_AUTO_CREATE)).isTrue();
+
+            // Check the target side behavior.
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onBind");
+
+            m = receiver.waitForNextMessage();
+            assertThat(m.getMethodName()).isEqualTo("onServiceConnected");
+            assertThat(m.getComponent()).isEqualTo(componentNameForClient);
+            // We don't need to check all the fields because these are tested else where.
+
+            // Now kill the service process.
+            ShellUtils.runShellCommand("su 0 killall %s", SUB2_PACKAGE);
+
+            // Check the target side behavior.
+            m = receiver.waitForNextMessage();
+
+            assertThat(m.getMethodName()).isEqualTo("onServiceDisconnected");
+            assertThat(m.getComponent()).isEqualTo(componentNameForClient);
+
+            receiver.ensureNoMoreMessages();
+        }
+    }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java
new file mode 100644
index 0000000..165d728
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.componentalias.tests;
+
+public final class ComponentAliasTestCommon {
+    private ComponentAliasTestCommon() {
+    }
+
+    public static final String TAG = "ComponentAliasTest";
+
+    public static final String MAIN_PACKAGE = "android.content.componentalias.tests";
+
+    public static final String SUB1_PACKAGE = "android.content.componentalias.tests.sub1";
+    public static final String SUB2_PACKAGE = "android.content.componentalias.tests.sub2";
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java b/tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java
new file mode 100644
index 0000000..535d9b8
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java
@@ -0,0 +1,70 @@
+/*
+ * 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.componentalias.tests.s;
+
+import static android.content.componentalias.tests.ComponentAliasTestCommon.TAG;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.componentalias.tests.ComponentAliasMessage;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.compatibility.common.util.BroadcastMessenger;
+
+public class BaseService extends Service {
+    private String getMyIdentity() {
+        return (new ComponentName(this.getPackageName(), this.getClass().getCanonicalName()))
+                .flattenToShortString();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "onStartCommand: on " + getMyIdentity() + " intent=" + intent);
+        ComponentAliasMessage m = new ComponentAliasMessage()
+                .setSenderIdentity(getMyIdentity())
+                .setMethodName("onStartCommand")
+                .setIntent(intent);
+        BroadcastMessenger.send(this, TAG, m);
+
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "onDestroy: on " + getMyIdentity());
+
+        ComponentAliasMessage m = new ComponentAliasMessage()
+                .setSenderIdentity(getMyIdentity())
+                .setMethodName("onDestroy");
+        BroadcastMessenger.send(this, TAG, m);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.i(TAG, "onBind: on " + getMyIdentity() + " intent=" + intent);
+
+        ComponentAliasMessage m = new ComponentAliasMessage()
+                .setSenderIdentity(getMyIdentity())
+                .setMethodName("onBind")
+                .setIntent(intent);
+        BroadcastMessenger.send(this, TAG, m);
+
+        return new Binder();
+    }
+}
diff --git a/core/java/android/uwb/SessionHandle.aidl b/tests/componentalias/src/android/content/componentalias/tests/s/Target00.java
similarity index 78%
copy from core/java/android/uwb/SessionHandle.aidl
copy to tests/componentalias/src/android/content/componentalias/tests/s/Target00.java
index 58a7dbb..64b91f5 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target00.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.componentalias.tests.s;
 
-package android.uwb;
-
-parcelable SessionHandle;
+public class Target00 extends BaseService {
+}
diff --git a/core/java/android/uwb/SessionHandle.aidl b/tests/componentalias/src/android/content/componentalias/tests/s/Target01.java
similarity index 78%
copy from core/java/android/uwb/SessionHandle.aidl
copy to tests/componentalias/src/android/content/componentalias/tests/s/Target01.java
index 58a7dbb..bd58999 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target01.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.componentalias.tests.s;
 
-package android.uwb;
-
-parcelable SessionHandle;
+public class Target01 extends BaseService {
+}
diff --git a/core/java/android/uwb/SessionHandle.aidl b/tests/componentalias/src/android/content/componentalias/tests/s/Target02.java
similarity index 78%
copy from core/java/android/uwb/SessionHandle.aidl
copy to tests/componentalias/src/android/content/componentalias/tests/s/Target02.java
index 58a7dbb..0ddf818 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target02.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.componentalias.tests.s;
 
-package android.uwb;
-
-parcelable SessionHandle;
+public class Target02 extends BaseService {
+}
diff --git a/core/java/android/uwb/SessionHandle.aidl b/tests/componentalias/src/android/content/componentalias/tests/s/Target03.java
similarity index 78%
copy from core/java/android/uwb/SessionHandle.aidl
copy to tests/componentalias/src/android/content/componentalias/tests/s/Target03.java
index 58a7dbb..0dbc050 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target03.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.componentalias.tests.s;
 
-package android.uwb;
-
-parcelable SessionHandle;
+public class Target03 extends BaseService {
+}
diff --git a/core/java/android/uwb/SessionHandle.aidl b/tests/componentalias/src/android/content/componentalias/tests/s/Target04.java
similarity index 78%
copy from core/java/android/uwb/SessionHandle.aidl
copy to tests/componentalias/src/android/content/componentalias/tests/s/Target04.java
index 58a7dbb..0994258 100644
--- a/core/java/android/uwb/SessionHandle.aidl
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target04.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.componentalias.tests.s;
 
-package android.uwb;
-
-parcelable SessionHandle;
+public class Target04 extends BaseService {
+}
diff --git a/tests/componentalias/src/com/android/compatibility/common/util/BroadcastMessenger.java b/tests/componentalias/src/com/android/compatibility/common/util/BroadcastMessenger.java
new file mode 100644
index 0000000..e01c2ef
--- /dev/null
+++ b/tests/componentalias/src/com/android/compatibility/common/util/BroadcastMessenger.java
@@ -0,0 +1,205 @@
+/*
+ * 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.compatibility.common.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.HandlerThread;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * Provides a one-way communication mechanism using a Parcelable as a payload, via broadcasts.
+ *
+ * Use {@link #send(Context, String, Parcelable)} to send a message.
+ * USe {@link Receiver} to receive a message.
+ *
+ * Pick a unique "suffix" for your test, and use it with both the sender and receiver, in order
+ * to avoid "cross-talks" between different tests. (if they ever run at the same time.)
+ *
+ * TODO: Move it to compatibility-device-util-axt.
+ */
+public final class BroadcastMessenger {
+    private static final String TAG = "BroadcastMessenger";
+
+    private static final String ACTION_MESSAGE =
+            "com.android.compatibility.common.util.BroadcastMessenger.ACTION_MESSAGE_";
+    private static final String ACTION_PING =
+            "com.android.compatibility.common.util.BroadcastMessenger.ACTION_PING_";
+    private static final String EXTRA_MESSAGE =
+            "com.android.compatibility.common.util.BroadcastMessenger.EXTRA_MESSAGE";
+
+    /**
+     * We need to drop messages that were sent before the receiver was created. We keep
+     * track of the message send time in this extra.
+     */
+    private static final String EXTRA_SENT_TIME =
+            "com.android.compatibility.common.util.BroadcastMessenger.EXTRA_SENT_TIME";
+
+    private static long getCurrentTime() {
+        return SystemClock.uptimeMillis();
+    }
+
+    private static void sendBroadcast(@NonNull Intent i, @NonNull Context context,
+            @NonNull String broadcastSuffix, @Nullable String receiverPackage) {
+        i.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        i.setPackage(receiverPackage);
+        i.putExtra(EXTRA_SENT_TIME, getCurrentTime());
+
+        context.sendBroadcast(i);
+    }
+
+    /** Send a message to the {@link Receiver} expecting a given "suffix". */
+    public static <T extends Parcelable> void send(@NonNull Context context,
+            @NonNull String broadcastSuffix, @NonNull T message) {
+        final Intent i = new Intent(ACTION_MESSAGE + Objects.requireNonNull(broadcastSuffix));
+        i.putExtra(EXTRA_MESSAGE, Objects.requireNonNull(message));
+
+        Log.i(TAG, "Sending: " + message);
+        sendBroadcast(i, context, broadcastSuffix, /*receiverPackage=*/ null);
+    }
+
+    private static void sendPing(@NonNull Context context,@NonNull String broadcastSuffix,
+            @NonNull String receiverPackage) {
+        final Intent i = new Intent(ACTION_PING + Objects.requireNonNull(broadcastSuffix));
+
+        Log.i(TAG, "Sending a ping");
+        sendBroadcast(i, context, broadcastSuffix, receiverPackage);
+    }
+
+    /**
+     * Receive messages sent with {@link #send}. Note it'll ignore all the messages that were
+     * sent before instantiated.
+     */
+    public static final class Receiver<T extends Parcelable> implements AutoCloseable {
+        private final Context mContext;
+        private final String mBroadcastSuffix;
+        private final HandlerThread mReceiverThread = new HandlerThread(TAG);
+
+        // @GuardedBy("mMessages")
+        private final ArrayList<T> mMessages = new ArrayList<>();
+        private final long mCreatedTime = getCurrentTime();
+        private boolean mRegistered;
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                // Log.d(TAG, "Received intent: " + intent);
+                if (intent.getAction().equals(ACTION_MESSAGE + mBroadcastSuffix)
+                        || intent.getAction().equals(ACTION_PING + mBroadcastSuffix)) {
+                    // OK
+                } else {
+                    throw new RuntimeException("Unknown broadcast received: " + intent);
+                }
+                if (intent.getLongExtra(EXTRA_SENT_TIME, 0) < mCreatedTime) {
+                    Log.i(TAG, "Dropping stale broadcast: " + intent);
+                    return;
+                }
+
+                // Note for a PING, the message will be null.
+                final T message = intent.getParcelableExtra(EXTRA_MESSAGE);
+                if (message != null) {
+                    Log.i(TAG, "Received: " + message);
+                }
+
+                synchronized (mMessages) {
+                    mMessages.add(message);
+                    mMessages.notifyAll();
+                }
+            }
+        };
+
+        /**
+         * Constructor.
+         */
+        public Receiver(@NonNull Context context, @NonNull String broadcastSuffix) {
+            mContext = context;
+            mBroadcastSuffix = Objects.requireNonNull(broadcastSuffix);
+
+            mReceiverThread.start();
+
+            final IntentFilter fi = new IntentFilter(ACTION_MESSAGE + mBroadcastSuffix);
+            fi.addAction(ACTION_PING + mBroadcastSuffix);
+
+            context.registerReceiver(mReceiver, fi, /* permission=*/ null,
+                    mReceiverThread.getThreadHandler(), Context.RECEIVER_EXPORTED);
+            mRegistered = true;
+        }
+
+        @Override
+        public void close() {
+            if (mRegistered) {
+                mContext.unregisterReceiver(mReceiver);
+                mReceiverThread.quit();
+                mRegistered = false;
+            }
+        }
+
+        /**
+         * Receive the next message with a 60 second timeout.
+         */
+        @NonNull
+        public T waitForNextMessage() {
+            return waitForNextMessage(60_000);
+        }
+
+        /**
+         * Receive the next message.
+         */
+        @NonNull
+        public T waitForNextMessage(long timeoutMillis) {
+            synchronized (mMessages) {
+                final long timeout = System.currentTimeMillis() + timeoutMillis;
+                while (mMessages.size() == 0) {
+                    final long wait = timeout - System.currentTimeMillis();
+                    if (wait <= 0) {
+                        throw new RuntimeException("Timeout waiting for the next message");
+                    }
+                    try {
+                        mMessages.wait(wait);
+                    } catch (InterruptedException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+                return mMessages.remove(0);
+            }
+        }
+
+        /**
+         * Ensure that no further messages have been received.
+         *
+         * Call it before {@link #close()}.
+         */
+        public void ensureNoMoreMessages() {
+            // Send a ping to myself.
+            sendPing(mContext, mBroadcastSuffix, mContext.getPackageName());
+
+            final T m = waitForNextMessage();
+            if (m == null) {
+                return; // Okay. Ping will deliver a null message.
+            }
+            throw new RuntimeException("No more messages expected, but received: " + m);
+        }
+    }
+}
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index af9786b..deff42a 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -38,6 +38,6 @@
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
-        "mockito-target-minus-junit4",
+        "mockito-target-extended-minus-junit4",
     ],
 }
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 672731c..899d268 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -319,12 +319,10 @@
 
             // The second subtag can either be a script or a region code.
             // If its size is 4, it's a script code, else it's a region code.
-            bool hasRegion = false;
             if (subtags[1].size() == 4) {
                 setScript(subtags[1]);
             } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
                 setRegion(subtags[1]);
-                hasRegion = true;
             } else {
                 fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.string());
                 return -1;
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp
index a19d183..01eb4f6 100644
--- a/tools/aapt/Android.bp
+++ b/tools/aapt/Android.bp
@@ -50,7 +50,6 @@
         "libbase",
         "libz",
     ],
-    group_static_libs: true,
 
     cflags: [
         "-Wall",
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 812e208..fecc7b3 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -769,7 +769,7 @@
     config.country[1] = 'S';
     config.orientation = ResTable_config::ORIENTATION_PORT;
     config.density = ResTable_config::DENSITY_MEDIUM;
-    config.sdkVersion = 10000; // Very high.
+    config.sdkVersion = SDK_CUR_DEVELOPMENT; // Very high.
     config.screenWidthDp = 320;
     config.screenHeightDp = 480;
     config.smallestScreenWidthDp = 320;
@@ -1306,16 +1306,30 @@
                                     splitName.string()).string());
                     }
 
+                    // For 'platformBuildVersionName', using both string and int type as a fallback
+                    // since it may be the code name of Android or the API level.
                     String8 platformBuildVersionName = AaptXml::getAttribute(tree, NULL,
                             "platformBuildVersionName");
+                    int32_t platformBuildVersionNameInt =
+                            AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionName", 0,
+                                                         NULL);
                     if (platformBuildVersionName != "") {
                         printf(" platformBuildVersionName='%s'", platformBuildVersionName.string());
+                    } else if (platformBuildVersionNameInt > 0) {
+                        printf(" platformBuildVersionName='%d'", platformBuildVersionNameInt);
                     }
 
+                    // For 'platformBuildVersionCode', using both string and int type as a fallback
+                    // since it may be the code name of Android or the API level.
                     String8 platformBuildVersionCode = AaptXml::getAttribute(tree, NULL,
                             "platformBuildVersionCode");
+                    int32_t platformBuildVersionCodeInt =
+                            AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionCode", 0,
+                                                         NULL);
                     if (platformBuildVersionCode != "") {
                         printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string());
+                    } else if (platformBuildVersionCodeInt > 0) {
+                        printf(" platformBuildVersionCode='%d'", platformBuildVersionCodeInt);
                     }
 
                     int32_t compileSdkVersion = AaptXml::getIntegerAttribute(tree,
@@ -1490,7 +1504,7 @@
                                         error.string());
                                 goto bail;
                             }
-                            if (name == "Donut") targetSdk = 4;
+                            if (name == "Donut") targetSdk = SDK_DONUT;
                             printf("sdkVersion:'%s'\n",
                                     ResTable::normalizeForOutput(name.string()).string());
                         } else if (code != -1) {
@@ -1512,7 +1526,12 @@
                                         error.string());
                                 goto bail;
                             }
-                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
+                            if (name == "Donut" && targetSdk < SDK_DONUT) {
+                                targetSdk = SDK_DONUT;
+                            } else if (name != "" && targetSdk == 0) {
+                                // Bump to current development version
+                                targetSdk = SDK_CUR_DEVELOPMENT;
+                            }
                             printf("targetSdkVersion:'%s'\n",
                                     ResTable::normalizeForOutput(name.string()).string());
                         } else if (code != -1) {
@@ -2122,7 +2141,7 @@
             }
 
             // Pre-1.6 implicitly granted permission compatibility logic
-            if (targetSdk < 4) {
+            if (targetSdk < SDK_DONUT) {
                 if (!hasWriteExternalStoragePermission) {
                     printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
                     printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
@@ -2149,7 +2168,7 @@
             }
 
             // Pre-JellyBean call log permission compatibility.
-            if (targetSdk < 16) {
+            if (targetSdk < SDK_JELLY_BEAN) {
                 if (!hasReadCallLogPermission && hasReadContactsPermission) {
                     printUsesPermission(String8("android.permission.READ_CALL_LOG"));
                     printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
@@ -2291,21 +2310,23 @@
             // the screen size support was introduced, so all default to
             // enabled.
             if (smallScreen > 0) {
-                smallScreen = targetSdk >= 4 ? -1 : 0;
+                smallScreen = targetSdk >= SDK_DONUT ? -1 : 0;
             }
             if (normalScreen > 0) {
                 normalScreen = -1;
             }
             if (largeScreen > 0) {
-                largeScreen = targetSdk >= 4 ? -1 : 0;
+                largeScreen = targetSdk >= SDK_DONUT ? -1 : 0;
             }
             if (xlargeScreen > 0) {
                 // Introduced in Gingerbread.
-                xlargeScreen = targetSdk >= 9 ? -1 : 0;
+                xlargeScreen = targetSdk >= SDK_GINGERBREAD ? -1 : 0;
             }
             if (anyDensity > 0) {
-                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
-                        || compatibleWidthLimitDp > 0) ? -1 : 0;
+                anyDensity = (targetSdk >= SDK_DONUT || requiresSmallestWidthDp > 0 ||
+                              compatibleWidthLimitDp > 0)
+                        ? -1
+                        : 0;
             }
             printf("supports-screens:");
             if (smallScreen != 0) {
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 257e96b..b9de11b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2475,11 +2475,10 @@
 {
     if (accessorCookie != NULL && fmt != NULL) {
         AccessorCookie* ac = (AccessorCookie*)accessorCookie;
-        int retval=0;
         char buf[1024];
         va_list ap;
         va_start(ap, fmt);
-        retval = vsnprintf(buf, sizeof(buf), fmt, ap);
+        vsnprintf(buf, sizeof(buf), fmt, ap);
         va_end(ap);
         ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n",
                             buf, ac->attr.string(), ac->value.string());
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index 955581c..857b25e 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -47,6 +47,7 @@
     SDK_Q = 29,
     SDK_R = 30,
     SDK_S = 31,
+    SDK_CUR_DEVELOPMENT = 10000,
 };
 
 #endif // H_AAPT_SDK_CONSTANTS
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 12dc156..740b44e 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -72,7 +72,6 @@
         "libidmap2_policies",
     ],
     stl: "libc++_static",
-    group_static_libs: true,
 }
 
 // ==========================================================
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/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 7518e70..384346b 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -57,6 +57,7 @@
   SDK_Q = 29,
   SDK_R = 30,
   SDK_S = 31,
+  SDK_CUR_DEVELOPMENT = 10000,
 };
 
 ApiVersion FindAttributeSdkLevel(const ResourceId& id);
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 145d7f8..40bbb36 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -92,7 +92,6 @@
 };
 
 const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
-constexpr int kCurrentDevelopmentVersion = 10000;
 constexpr int kNeverForLocation = 0x00010000;
 
 /** Retrieves the attribute of the element with the specified attribute resource id. */
@@ -331,7 +330,7 @@
     ConfigDescription config;
     config.orientation = android::ResTable_config::ORIENTATION_PORT;
     config.density = android::ResTable_config::DENSITY_MEDIUM;
-    config.sdkVersion = kCurrentDevelopmentVersion; // Very high.
+    config.sdkVersion = SDK_CUR_DEVELOPMENT;  // Very high.
     config.screenWidthDp = 320;
     config.screenHeightDp = 480;
     config.smallestScreenWidthDp = 320;
@@ -621,7 +620,7 @@
     // Detect the target sdk of the element
     if  ((min_sdk_name && *min_sdk_name == "Donut")
         || (target_sdk_name && *target_sdk_name == "Donut")) {
-      extractor()->RaiseTargetSdk(4);
+      extractor()->RaiseTargetSdk(SDK_DONUT);
     }
     if (min_sdk) {
       extractor()->RaiseTargetSdk(*min_sdk);
@@ -629,7 +628,7 @@
     if (target_sdk) {
       extractor()->RaiseTargetSdk(*target_sdk);
     } else if (target_sdk_name) {
-      extractor()->RaiseTargetSdk(kCurrentDevelopmentVersion);
+      extractor()->RaiseTargetSdk(SDK_CUR_DEVELOPMENT);
     }
   }
 
@@ -746,21 +745,23 @@
     // the screen size support was introduced, so all default to
     // enabled.
     if (small_screen_temp  > 0) {
-      small_screen_temp  = target_sdk >= 4 ? -1 : 0;
+      small_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
     }
     if (normal_screen_temp  > 0) {
       normal_screen_temp  = -1;
     }
     if (large_screen_temp  > 0) {
-      large_screen_temp  = target_sdk >= 4 ? -1 : 0;
+      large_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
     }
     if (xlarge_screen_temp  > 0) {
       // Introduced in Gingerbread.
-      xlarge_screen_temp  = target_sdk >= 9 ? -1 : 0;
+      xlarge_screen_temp = target_sdk >= SDK_GINGERBREAD ? -1 : 0;
     }
     if (any_density_temp  > 0) {
-      any_density_temp  = (target_sdk >= 4 || requires_smallest_width_dp > 0
-          || compatible_width_limit_dp > 0) ? -1 : 0;
+      any_density_temp = (target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
+                          compatible_width_limit_dp > 0)
+                             ? -1
+                             : 0;
     }
 
     // Print the formatted screen info
@@ -2030,7 +2031,7 @@
   auto write_external_permission = ElementCast<UsesPermission>(
       FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
 
-  if (target_sdk() < 4) {
+  if (target_sdk() < SDK_DONUT) {
     if (!write_external_permission) {
       PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
       insert_write_external = true;
@@ -2053,7 +2054,7 @@
   }
 
   // Pre-JellyBean call log permission compatibility.
-  if (target_sdk() < 16) {
+  if (target_sdk() < SDK_JELLY_BEAN) {
     if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
         && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
       PrintPermission("android.permission.READ_CALL_LOG",
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 1bb0696..63b2fcd 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -163,6 +163,31 @@
   return true;
 }
 
+static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics* diag) {
+  constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
+  constexpr const char* kIsSplitRequired = "isSplitRequired";
+
+  xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kRequiredSplitTypes);
+  if (attr != nullptr) {
+    // Now inject the android:isSplitRequired="true" attribute.
+    xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsSplitRequired);
+    if (attr != nullptr) {
+      if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
+        // The isFeatureSplit attribute is false, which conflicts with the use
+        // of "featureSplit".
+        diag->Error(DiagMessage(el->line_number)
+                    << "attribute 'requiredSplitTypes' used in <manifest> but "
+                       "'android:isSplitRequired' is not 'true'");
+        return false;
+      }
+      // The attribute is already there and set to true, nothing to do.
+    } else {
+      el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsSplitRequired, "true"});
+    }
+  }
+  return true;
+}
+
 static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
                            SourcePathDiagnostics* diag) {
   xml::Attribute* attr = el->FindAttribute({}, "package");
@@ -329,6 +354,7 @@
   // Manifest actions.
   xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
   manifest_action.Action(AutoGenerateIsFeatureSplit);
+  manifest_action.Action(AutoGenerateIsSplitRequired);
   manifest_action.Action(VerifyManifest);
   manifest_action.Action(FixCoreAppAttribute);
   manifest_action.Action([&](xml::Element* el) -> bool {
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 3cdb27c..ac23c3d 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -35,6 +35,7 @@
         echo
         echo "If your change contains no confidential details (such as security fixes), please"
         echo "upload and merge this change at https://android-review.googlesource.com/."
+        echo "Else add a tag 'Ignore-AOSP-First:' with the reason to bypass AOSP."
         echo
         exit 1
     fi
diff --git a/tools/lint/OWNERS b/tools/lint/OWNERS
new file mode 100644
index 0000000..7c04519
--- /dev/null
+++ b/tools/lint/OWNERS
@@ -0,0 +1,5 @@
+brufino@google.com
+jsharkey@google.com
+
+per-file *CallingSettingsNonUserGetterMethods* = file:/packages/SettingsProvider/OWNERS
+
diff --git a/tools/lint/README.md b/tools/lint/README.md
index d661bc4..df2fe2a 100644
--- a/tools/lint/README.md
+++ b/tools/lint/README.md
@@ -30,21 +30,20 @@
 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.
+- If you want to build lint reports for more than 1 module and they include a common module in their
+  `defaults` field, 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 Docs](https://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)
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
index 5736a80..900c214 100644
--- 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
@@ -30,7 +30,8 @@
             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
+            CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+            CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED
     )
 
     override val api: Int
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..fe567da
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.getNameLocation(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.ERROR,
+                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/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt
new file mode 100644
index 0000000..e72f384
--- /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: Error: \
+                        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(),
+                                                         ~~~~~~
+                        1 errors, 0 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: Error: \
+                        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(),
+                                                           ~~~~~~~~
+                        1 errors, 0 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: Error: \
+                        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(),
+                                                              ~~~~~~~~
+                        1 errors, 0 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: Error: \
+                        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: Error: \
+                        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(),
+                                                             ~~~~~~~~~
+                        2 errors, 0 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", "")
+}
diff --git a/tools/split-select/Android.bp b/tools/split-select/Android.bp
index c12fc6a..5402657 100644
--- a/tools/split-select/Android.bp
+++ b/tools/split-select/Android.bp
@@ -48,7 +48,6 @@
         "libbase",
         "libz",
     ],
-    group_static_libs: true,
 
     target: {
         windows: {